前端优化的途径有很多,按粒度大致可以分为两类,第一类是页面级别的优化,例如 HTTP请求数、脚本的无阻塞加载、内联脚本的位置优化等 ;第二类则是代码级别的优化,例如 Javascript中的DOM 操作优化、CSS选择符优化、图片优化以及 HTML结构优化等等
{
宽(width)
对齐方式 align (left center right)
表格边框宽度 (border)
单元边沿与其内容之间的空白 (cellpadding)
单元格之间的空白 (cellspacing)
合并单元格 (跨行合并:rowspan="合并单元格个的个数"
跨列合并:colspan="合并单元格个的个数" )
外侧边框的哪个部分是可见的(void、above、below、hsides...)
内侧边框的哪个部分是可见的(none、groups、rows、cols、all)
表格的摘要(summary)
}
标签
1.块级标签 块级元素 :独占一行 默认宽度100% 可以设置宽高
块级元素:-、p、div、ul、ol、li...
宽度默认100%;默认独占一行;可以直接设置 宽 高 边距 填充
2.行内标签 行内元素 :并排显示 默认宽度是内容宽度 不可以直接设置宽高
行内元素:a,strong,b,em,i,del,s,ins,u,span...
宽度自动;默认并排显示,不能直接设置 宽 高 边距 填充
3.行内块元素 :可以设置宽高 并排显示
行内块元素:img、input
宽度自动;默认并排显示,可以直接设置 宽 高 边距 填充,自带2-3像素的边距
三种转换:
元素->行内: style=" display:inline; "
元素->块: style=" display:block; "
元素->行内块: style=" display:inline-block; "
背景图(css 中)
background: slateblue; 设置背景色
background-image: url("./images/sgwe.jpg"); 设置背景图片
background-repeat: no-repeat; 设置图片不重复
background-position: ; 水平方向 垂直方向
background-position-x: ; 设置水平位置
background-position-y: ; 设置竖直位置
background-position: 10px 100px; 如下
background-position: x y; 没写哪个哪个就是默认全局居中
background-position: center top; 设置位置在头部的中间
background-attachment: fixed; 设置背景图片附着(固定)
background-size: cover; 平铺在整个容器中 auto 图片本身大小
border: 1px solid #000; 设置边框 粗细 实线/虚线(solid/dashed) 颜色
border-radius: 50%; 设置边框圆角 (单位 px或% 都行)
box-shadow:inset 5px 5px 5px green; 设置元素阴影 内阴影inset 不写就是外阴影 (三个值:横向位置 纵向位置 虚化)
Background-size:100% 100%; 背景图一个百分之百占比
transparent 透明色
例:将一个P标签做成一个球
background-image: url("./images/sgwe.jpg");
/* 设置背景图片 */
background-repeat: no-repeat;
/* 设置背景图片平铺 */
/* background-position:50 ; 水平方向 垂直方向 */
/* background-position: center top; */
/* 在头部的中间 */
/* background-position: 10px 100px; */
/* background-position: x y;没写哪个哪个就是默认全局居中 */
/* 设置背景图片位置 */
background-attachment: fixed;
/* 设置背景图片附着 */
/* background: slateblue url("./images/sgwe.jpg") no-repeat fixed 250px 0; */
background-size: cover;
/* 设置背景图片尺寸 需要单独写出来*/
object-fit CSS 属性指定可替换元素的内容应该如何适应到其使用的高度和宽度确定的框。
可以通过使用 object-position 属性来切换被替换元素的内容对象在元素框内的对齐方式。
contain:被替换的内容将被缩放,以在填充元素的内容框时保持其宽高比。 整个对象在填充盒子的同时保留其长宽比,因此如果宽高比与框的宽高比不匹配,该对象将被添加“黑边”。
cover:被替换的内容在保持其宽高比的同时填充元素的整个内容框。如果对象的宽高比与内容框不相匹配,该对象将被剪裁以适应内容框。
fill:被替换的内容正好填充元素的内容框。整个对象将完全填充此框。如果对象的宽高比与内容框不相匹配,那么该对象将被拉伸以适应内容框。
none:被替换的内容将保持其原有的尺寸。
scale-down:内容的尺寸与 none 或 contain 中的一个相同,取决于它们两个之间谁得到的对象尺寸会更小一些。
vertical-align: middle;
导航栏
nav 标签为导航栏标签
导航栏内用ul il 写
复制付费文本
方法1:F12 F1 设置禁用JS
方法2:F12 元素 事件帧监听 删除复制事件
方法3:找到HTML中存放内容的段落,找到父级,添加一个id或者class,然后在控制台打印console.log(document.getElementById('自建ID').innerText)
CSS
选择器
1.类选择器
在此例中,所有带有 class="center" 的 HTML 元素将为红色且居中对齐:
例1 .center {
text-align: center;
color: red;
}
例2
这个标题不受影响
本段将是红色并居中对齐。
本段将是红色、居中对齐,并使用大字体。
2.标签选择器
页面上的所有 标签都将居中对齐,并带有红色文本颜色:
p {
text-align: center;
color: red;
}
3.id选择器(注意:id名称不能以数字开头)
这条 CSS 规则将应用于 id="para1" 的 HTML 元素:
#para1 {
text-align: center;
color: red;
}
4.通配符选择器
下面的 CSS 规则会影响页面上的每个 HTML 元素:
* {
text-align: center;
color: blue;
}
5.分组选择器
分组选择器选取所有具有相同样式定义的 HTML 元素
例3
本段将是红色
本段将是红色
6.后代选择器(包含选择器)
用来选择元素或元素组的后代,写法就是把外层标签写在前面,内层标签写在后面,中间用空格分开。当标签发生嵌套的时候,内层标签就成为外层标签的后代;
aaaaaaa
(红)
bbbbbbb
(红)
ccccccc
(红)
7.子元素选择器
只能选择作为某元素子元素的元素,其写法就是把父级标签写在前面,子集标签写在后面,中间跟一个>进行连接,注意,符号左右两侧各保留一个空格;
8.:after 选择器
:after 选择器向选定元素的最后子元素后面插入内容,使用content 属性来指定要插入的内容
/*在每个p标签后都会添加一个 - 注意我 */
我的名字是 Donald
我住在 Ducksburg
注意: :after在IE8中运行,必须声明 !DOCTYPE
9.属性选择器
*[title] {color:red;} /*所有包含title属性的元素为红色*/
a[href] {color:red;} /*有herf属性的a标签颜色为红色*/
a[href][title] {color:red;} /*同时有herf 和 title属性的a 标签为红色*/
*[type|="wer"] {color: blue;} /*type属性值为wer的标签会被选择*/
{
color: red;
}
为 XML 文档使用属性选择器
a[href="#"] {color: red;} /*根据属性值选择*/
a[href="#"][title="W3School"] {color: red;} /*与上类似*/
p[class="i w"] /*类为i w 的P标签才会被选择*/
{
color: red;
}
p[class~="i"] /*类中有i 的 p 标签就会被选择*/
{
color: red;
}
伪类选择器
伪元素为行内元素,可以转换为其他类型元素。
伪类选择器: 用于向某些选择器添加特殊的效果,比如给链接添加特殊效果,或选择第n个元素。
伪类选择器书写最大的特点是用冒号(:)表示
1.链接伪类选择器:
:link 选择所有未被访问的链接
:visited 选择所有已被访问的链接
:hover 选择鼠标指针位于其上的链接
:active 选择活动链接(鼠标按下未弹起的链接)
:hover 只能父级控制子级 ,若是兄弟级控制兄弟级, 写法: #a1:hover~#a2{}(注意hover后波浪线) 注意,hover效果 可以用display:none写,可以用overflow:fiddenxie写 不能用opacity:0 :hover 前不能有空格!!!
例1:
好好学习
2.focus伪类选择器用于选取获取焦点的表单元素,焦点就是光标 (仅用于 文本框中,有聚焦作用)
例2:
(outline:none; 外部边框为空)
3. .p::after{} .p::before{} 在元素后/前添加元素 元素内容为 content:"";
4.结构伪类选择器
p:first-child{} 匹配元素中的第一个元素(选择器选中的是父元素中的子元素)E:last-child 匹配元素中的最后一个元素
E:nth-child(n) 匹配元素中的第n个元素,这个n可以是数字也可以是公式也可以是关键字 公式:
2n :求偶数
2n+1:奇数
5n:5的倍数 5-10-15-20-25
n+5 :从第5个开始
-n+5:前5个
关键字:只有odd 和 even 两个关键字(奇数偶数)
优先级
优先级:!important > 行内样式 > 内链样式 > 外部引入 ( !important 可直接添加在css样式中 )
后代选择器 > 子类选择器; 为同种选择器时,哪个的描述多哪个优先级高。
id 相当于身份证号; class 相当于小名。
样式 / 属性
引入css样式的三种类型:行内样式、内嵌样式(利用选择器)、外部引入。
外部引入的CSS:新建css文件,在html文件中标签中添加 标签。在 href="" 中添加css文件路径。
1.字体
color: aquamarine;
/* 字体颜色 */
background-color: #d5d5d5;
/* 背景色 */
font-size: 20px; 因为该属性的值会被用于计算em和ex长度单位,定义该值可能改变其他元素的大小。
/* 字体大小 */
font-weight:
定义字体粗细:normal
正常粗细。与400等值。
bold
加粗。 与700等值。
lighter
比从父元素继承来的值更细(处在字体可行的粗细值范围内)。
bolder
比从父元素继承来的值更粗 (处在字体可行的粗细值范围内)。
②font-family:
定义字体
margin: 10px 20px 30px 40px;
/* 外边距 (顺时针为 上右下左) */
padding: 20px;
/* 内边距 */
font-family: "楷体";
/* 字体样式 */
font-style: italic;
/* 字体倾斜 */
font-weight: bold;
/* 字体粗细 */
text-align: center;
/* 字体对齐方式 */ 文字居中对齐
text-decoration: underline;
/* 字体下划线 */
text-indent: 2em;
/* 首行缩进 */
letter-spacing: 10px;
/* 设置字间距 */
line-height: 60px;
/* 设置行高 */
text-shadow: 30px 30px 30px blue;
/* 设置文本阴影:水平方向偏移量,垂直方向偏移量,阴影面积,阴影颜色 */
line-height: 50px ; ***其他元素使用频率也很高
/*设置行高*/
border-radius;
改边框厚度 改边框圆滑
background:transparent;
文本框透明
placeholder:
占位提示文字
margin: 100px auto;
/*强制文字在一行文本框内*/
word-wrap:break-word; //文字溢出换行
2.div
border: 10px solid black;
/* 虚线:dotted dashed */
/* 边框:宽度 实线 颜色 */
cursor:pointer //鼠标移上变手
3.a
target: (不是css属性,直接写在a标签内)
_blank
_parent
_self
_top
framename
规定在何处打开链接
cursor:pointer //鼠标移上变手
a:link,定义正常链接的样式
a:visited,定义已访问过链接的样式
a:hover,定义鼠标悬浮在链接上时的样式
a:active,定义鼠标点击链接时的样式
注意:
在 CSS 定义中,a:hover 必须被置于 a:link 和 a:visited 之后,才是有效的。
在 CSS 定义中,a:active 必须被置于 a:hover 之后,才是有效的。
text-decoration 属性是用来设置 a 标签的划线属性的。其属性值有:
none:去掉下划线
underline:设置下划线
overline:在文本上方设置线条
line-through:在文本中间设置线条
initial:默认值
inherit:从父元素中继承
4.列表样式
list-style-type 属性的常见属性值的描述:
none:不使用项目符号
disc:实心圆
circle:空心圆
square:实心方块
decimal:阿拉伯数字
lower-alpha:小写英文字母
upper-alpha:大写英文字母
lower-roman:小写罗马数字
upper-roman:大写罗马数字
其他
display:none;
/*隐藏该区域*/
opacity: 0; (调整透明度)
/*隐藏该区域(值为0.透明度为0;值为1,透明度为100%)*/
background-color: rgba(255, 248, 220, 0.4);
/*调整颜色透明度 (r,g,b,a) a值为透明度 */
z-index:;
调整元素显示优先级,必须配合定位使用
box-sizing: border-box;
盒子大小等于你设置的大小
border-radius: 5px; / 5%;
设置边框圆角
background:linear-gradient(red, green, blue);
background-image: radial-gradient(red 5%, yellow 15%, green 60%);
背景渐变
Background-size:100% 100%;
背景图一个百分之百占比
给标签前添加logo
盒子突起效果:
box-shadow:inset 0px 0px 10px black;
立体效果:
box-shadow:5px 5px 30px 10px black;
cursor:pointer //鼠标移上变手
position: absolute;
top:50%;
left:50%;
transform: translate(-50%,-50%);
/*将页面移到中央*/
button disabled = true 按钮不可按 按钮属性,不是css
transparent 透明色
list-style:none; 去除无序列表的符号
object-fit CSS 属性指定可替换元素的内容应该如何适应到其使用的高度和宽度确定的框。
可以通过使用 object-position 属性来切换被替换元素的内容对象在元素框内的对齐方式。
contain:被替换的内容将被缩放,以在填充元素的内容框时保持其宽高比。 整个对象在填充盒子的同时保留其长宽比,因此如果宽高比与框的宽高比不匹配,该对象将被添加“黑边”。
cover:被替换的内容在保持其宽高比的同时填充元素的整个内容框。如果对象的宽高比与内容框不相匹配,该对象将被剪裁以适应内容框。
fill:被替换的内容正好填充元素的内容框。整个对象将完全填充此框。如果对象的宽高比与内容框不相匹配,那么该对象将被拉伸以适应内容框。
none:被替换的内容将保持其原有的尺寸。
scale-down:内容的尺寸与 none 或 contain 中的一个相同,取决于它们两个之间谁得到的对象尺寸会更小一些。
居中显示
1.整体居中 (建议使用)
.d2{
width: 300px;
height: 300px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
2.整体居中显示 (不建议使用)
.d2{
width: 200px;
height: 200px;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
3.设置行内居中:
(1).设置行高lint-height:;为父容器高度,行内自动垂直居中
(2).padding、margin
(3).定位
(4).position: absolute; top:0; bottom:0;
4.flex布局
5.vertical-align 属性设置元素的垂直对齐方式
baseline 默认。元素放置在父元素的基线上。
sub 垂直对齐文本的下标。
super 垂直对齐文本的上标
top 把元素的顶端与行中最高元素的顶端对齐
text-top 把元素的顶端与父元素字体的顶端对齐
middle 把此元素放置在父元素的中部。
bottom 把元素的顶端与行中最低的元素的顶端对齐。
text-bottom 把元素的底端与父元素字体的底端对齐。
% 使用 "line-height" 属性的百分比值来排列此元素。允许使用负值。
inherit 规定应该从父元素继承 vertical-align 属性的值。
盒模型
设置盒模型的margin等属性时
值若唯一x,则上下左右均为x;
值若为二x,y,则上下为x,左右为y;
值若为三,x,y,z, 则上为x,左右为y,下为z;
注意:在已设置宽高的盒模型中添加内外边距后,盒模型会变大,但是可用空间还是原来的宽高;
在已添加内外边距盒模型的css中添加box-sizing: border-box;时将强制把盒模型的大小变回原本设置的宽高,盒模型中可用空间将被缩小;
iconfont
三种方法 (以字体的方式调整)
1.中用 导入css文件 ; 将代码复制在标签中( ,可以再对i标签进行修饰)
2.
浮动
可以让块级元素并排显示,浮动不会影响前面的元素 float:left;
高度坍塌:(父元素高度为0)
正常文档流的父元素,里面的所有子元素都为浮动元素的时候,父元素的高度不会被子元素所撑开
清除浮动:
1.父元素设置死高 /* 不建议使用 */
2.父元素设置溢出隐藏(没有溢出元素) 内容增多的时候容易造成不会自动换行导致内容被隐藏掉,无法显示要溢出的元素
/* 不建议使用 */
3.在父元素的结束标签前面添加一个空的块级元素,设置clear: both;属性,本质就是闭合浮动, 就是让父盒子闭合出口和 入口,不让子盒子出来
4.父元素类名:::after{
display:block;
clear: both;
content:"";
} /* 清除浮动 */
clear 属性:
left; 在左侧不允许浮动元素。
right; 在右侧不允许浮动元素。
both; 左右两侧都不允许浮动。
none; 默认值。允许浮动出现在两侧。
inherit; 规定应该从父元素中继承clear属性值。
浮动元素超过父盒子宽度就会自动换行
边距重合
边距重合:
正常文档流的父元素里面的两个子元素在垂直方向相遇,上面的设置下边距,下面的设置上边距,两个中间的边距不会相加,只会 取最大值。
具体的叠加规则是:正正取大值、正负值相加、负负最负值
解决方法:直接给margin-bottom与margin-top其中一个元素两者之和
边距传递
边距传递:
正常文档流的父元素里面的第一个子元素设置上边距时,这个上边距会传递给父级元素。
解决方法:
1、用父元素padding代替子元素margin /* 不推荐使用*/
2、父元素透明边框 border:1px solid transparent; /*不推荐使用*/
* 3、子元素绝对定位 postion:absolute;
4、父元素 overflow:hidden; (溢出隐藏) /* 可以使用 */
5、父或子元素加 float:left;
6、父或子元素加 display:inline-block; /*不推荐使用*/
7、在盒子内添加一个空的伪元素做盒内第一个元素
.bx::before{
content:'';
width:100%;
height:1px; /*设置高度为1px*/
margin-bottom:-1px; /*设置底外边框为 -1px 与高度抵消*/
display:block;
}
溢出隐藏
overflow属性规定当内容溢出元素框时发生的事情,有四个参数:
overflow: visible; 内容不会被修剪,会呈现在元素框之外,这是默认值。
overflow: hidden; 内容会被修剪,但是浏览器不会显示供查看的滚动条。
overflow: scroll; 内容会被修剪,但是浏览器会显示滚动条以便查看其余内容。
overflow: auto; 自动。由浏览器决定如何显示,如超出则会显示滚动条。
overflow-y: scroll; 设置仅在y轴的超出滚动条。
overflow: hidden;
/* 文字溢出隐藏 */
white-space: nowrap;
/* 不换行,内容在一行显示 */
text-overflow: ellipsis; /*!!!需要搭配overflow:hiddenl;使用*/
/* 溢出文字为省略号 */
word-wrap:break-word; //文字溢出换行
定位 Position
定位=定位模式 + 边偏移
position 属性指定了元素的定位类型:static; relative(相对定位) fixed(固定定位); absolute(绝对定位); sticky(粘性 定位)
static 定位 静态定位的元素不会受到 top, bottom, left, right影响
fixed(固定定位) 元素的位置相对于浏览器窗口是固定位置,即使窗口是滚动的它也不会移动:
注意: Fixed 定位在 IE7 和 IE8 下需要描述 !DOCTYPE 才能支持。
Fixed定位使元素的位置与文档流无关,因此不占据空间。
Fixed定位的元素和其他元素重叠.
relative 相对定位 他是相对于自己原来的位置来移动的,移动相对定位元素,但它原本所占的空间不会改变
例1:div
{
position:relative; /*在原来位置的基础上下移左移了30px*/
left:30px;
top:30px;
}
absolute 绝对定位 子绝父相:如果子级使用绝对定位,父级则需要相对定位。
1、自己绝对定位,不会占有位置,可以放到父盒子里面的任何一个地方,不会影响其他的兄弟盒 子,会和其他盒子重叠。
2、父盒子需要加定位限制子盒子在父盒子内显示。
3、父盒子布局时,需要占有位置,因此父亲只能是相对定位。
sticky 粘贴定位 定位表现为在跨越特定阈值前为相对定位,之后为固定定位.特定阈值指的是 top, right, bottom 或 left 之一,换言之,指定 top, right, bottom 或 left 四个阈值其中之一,才可使粘性定位生 效。否则其行为与相对定位相同
将盒子固定在版心右侧位置。
1、让固定定位的盒子left:50%,走到浏览器可视区(相当于版心)的一版位置。
2、让固定定位的盒子margin-left:版心宽度的一半距离。多走版心宽度的一般位置。
定位的叠放次序:z-index
在使用定位布局时,可能会出现盒子重叠的情况。此时,可以使用z-index来控制盒子的前后次序(z轴)
z-index:1;
1、数值可以是正整数、负整数或是0,默认是auto,数值越大,盒子越靠上
2、如果属性值相同,则按照书写顺序,后来者居上。
3、数字后面不能加单位。
4、只有定位的盒子才有z-index属性
拓展:
定位特殊性:绝对定位和固定定位也和浮动类似
1、行内元素添加绝对或者固定定位,可以直接设置高度和宽度。
2、块级元素添加绝对或者固定定位,如果不给宽度或者高度,默认大小是内容的大小。
3、浮动元素,只会压住它下面标准流的盒子,但是不会压住下面标准流盒子里面的文字(图片),但是绝对定位(固定定位)会压住下面标准流所有内容。
span的字会跟在div后面
原因:浮动之所以不会压住文字,因为浮动产生的目的最初是为了做文字环绕效果的。文字会围绕浮动元素
overflow-y 指定如何处理顶部/底部边缘的内容溢出元素的内容区域
visible 不裁剪内容,可能会显示在内容框之外。
hidden 裁剪内容 - 不提供滚动机制。
scroll 裁剪内容 - 提供滚动机制。
auto 如果溢出框,则应该提供滚动机制。
no-display 如果内容不适合内容框,则删除整个框。
no-content 如果内容不适合内容框,则隐藏整个内容。
二级导航
在导航栏设置无序列表,在每一行设置二级列表。一般状态二级导航为display: none;(隐藏内容)。设置一级导航的hover属性;当鼠标经过时取消隐藏。
控制鼠标经过的hove加在一级导航的div中。hover后跟要控制的元素 例:
.div1:hover ul{ /*鼠标经过.div1元素时,控制的元素是ul*/
display: block;
}
2D
旋转 transform: rotate(*deg);
倾斜 transform: skew(); skewX / skewY
平移 transform:translate(); X / Y
缩放 transform: scale(); X,Y
平滑过渡 transition: 1s; //全部平滑过渡 transition: all 1s;
//若要单个控制平滑 transition: width 1s; (单独控制宽度的平滑时间)
position: absolute;
top:50%;
left:50%;
transform: translate(-50%,-50%);
/*将页面移到中央*/
动画
添加动画:1. @keyframes 动画名 {
from{}
to{}
}
2. @keyframes 动画名 {
0%{
}
50%{
}
100%{
}
}
绑定动画: animation: 动画名 动画持续时间 延迟多少时间播放 动画重复次数(infinite持续播放)(linear匀速播放) 动画结束位置(forwards留在原位);
animation-name: example; 动画名
animation-duration: 5s; 动画时间
animation-timing-function: linear; 规定速度曲线(linear匀速 ease慢块慢 ease-in慢速开始 ease-out慢速结束 ease-in-out慢速开始和结束 cubic-bezier(n,n,n,n)0 到 1 的数值)
animation-delay: 2s; 动画延迟
animation-iteration-count: infinite; 播放次数(持续播放 infinite;)
animation-direction: alternate; 向前播放、向后播放还是交替播放
注意:使用移动动画的元素必须添加相对定位
动画延迟可以为负值,动画则为从已播放的 N 秒开始
fiex布局
注意,设为 Flex 布局以后,子元素的float、clear 等属性将失效。
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)
主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end
项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size
项目默认沿主轴排列。单个项目占据的主轴空间叫做main size(项目宽度),占据的交叉轴空间叫做cross size(项目高度)
弹性盒子内一般不设置死的宽高(突出弹性的特点)
子元素设置flex:1;即可铺满盒子 (若不给死宽高使用比例,则需要没有死宽高的子元素都设置比例)
设置在父盒子的属性
以下6个属性设置在父容器上。
* flex-direction :主轴方向
* flex-wrap :是否换行,怎么换行
* flex-flow :flex-flow 属性是 flex-direction 和 flex-wrap 属性的复合属性。
* justify-content: 属性定义了项目在主轴上(X)的对齐方式。
* align-items:属性定义项目在交叉轴上(Y)如何对齐。
* align-content:属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
*flex-direction属性值
row(默认值):(X)主轴为水平方向,起点在左端。
row-reverse:(X)主轴为水平方向,起点在右端。
column:(Y)主轴为垂直方向,起点在上沿。
column-reverse:(Y)主轴为垂直方向,起点在下沿。
*flex-wrap属性值
nowrap(默认):不换行。(项目总宽度如果超出盒子宽度,项目宽度会被挤压【不会超出盒子】)
wrap:换行,第一行在上方。
wrap-reverse:换行,第一行在下方。
*flex-flow属性
flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为 nowrap
flex-flow:flex-direction flex-warp;
*justify-content属性
justify-content属性定义了项目在主轴上(X轴)的对齐方式
flex-start(默认值):左对齐
flex-end:右对齐
center: 居中
space-between:两端对齐,项目之间的间隔都相等。
space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。(项目之间的间隔为左右两个项目间隔之和)
space-evenly 间隔相等
*align-items属性
align-items属性定义项目在交叉轴上(Y轴)如何对齐
flex-start:交叉轴的起点对齐。(上端对齐)
flex-end:交叉轴的终点对齐。(下端对齐)
center:交叉轴的中点对齐。(上下居中)
baseline: 项目的第一行文字的基线对齐。
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。
*align- content属性
align- content属性定义了行的对齐方式。如果项目只有一根轴线,该属性不起作用。
该属性中的六个属性值与justify-content中的六个属性意思相似,不同之处在于justify-content沿主轴方向的作用于单个子元素,而align-content沿交叉轴方向作用于行。
flex-start:与交叉轴的起点对齐。(所有项目上对齐)
flex-end:与交叉轴的终点对齐。(所有项目下对齐)
center:与交叉轴的中点对齐。(所有项目上下居中,上下项目间没间隔)
space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。(所有项目上下排满,项目间有间隔,项目间间隔为两个单项目间隔)
space-around:每根轴线两侧的间隔都相等。所以轴线之间的间隔比轴线与边框的间隔大一倍。()
stretch(默认值):轴线占满整个交叉轴。(项目若没设高则会拉长占满)
设置在项目上的属性(子元素上)
* order : 属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。
* flex-grow: 属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
* flex-shrink: 属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
* flex-basis: 属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
* flex: 属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
* align-selff:属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch
*order属性
属性值一般为number类型也可以是initial(默认值),inherit(从父元素继承的值)为设置弹性盒对象元素的顺序:数字越小越靠前。取值0.1.2...
*flex-grow属性
如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。
*flex-shrink属性
属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小
*flex-basis属性
定义了在分配多余空间之前,项目占据的主轴空间(main size)相当于宽度,优先级大于自身设定的宽度。
* flex属性
是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
flex:1;0占有空间 ,1缩放比例,100px固定值
这个0 1 auto是什么意思,
flex-grow:表示当子元素的空间小于父元素的空间时,如何处理剩余空间,默认值为0表示不占有剩余空间;
felx-shrink:表示当子元素的空间大于父元素的空间时,如何缩小子元素,默认值为1表示等比缩小
flex-basis :用于设置项目占据的主轴空间,设置为auto表示项目占据的主轴大小等于项目的实际内容大小,设置为固定值表示项目占据的主轴大小等于固定值
*align-self属性
允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性(优先级高)。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
移动端布局(响应式)
* 视口:视口(viewport)就是浏览器显示页面内容的屏幕区域,视口可以分为视觉视口,布局视口和理想视口
* 布局视口:布局视口是指网页的宽度,一般移动端浏览器都默认设置了布局视口的宽度。移动端浏览器之所以采用这样的默认设置,是为了解决早期的PC端页面在手机上显示的问题。根据设备的不同,布局视口的默认宽度有可能是768px、980px或1024px等,这个宽度并不适合在手机屏幕中展示。(当移动端浏览器展示PC端网页内容时,由于移动端设备屏幕比较小,不能像PC端浏览器那样完美地展示网页,这正是布局视口存在的问题。这样的网页在手机的浏览器中会出现左右滚动条,用户需要左右滑动才能查看完整的一行内容)
* 视觉视口:用户正在看到的网站区域。可以通过缩放操作视觉视口。但不会影响布局视口,布局视口依然保持原来的宽度。
* 理想视口:理想视口是指对设备来讲最理想的视口尺寸。采用理想视口的方式,可以使网页在移动端浏览器上获得最理想的浏览和阅读的宽度。在理想视口情况下,布局视口的大小和屏幕宽度是一致的,这样就不需要左右滚动页面了。在开发中,为了实现理想视口,需要给移动端页面添加标签配置视口,通知浏览器来进行处理。
meat视口标签
name=“viewport”:意为视口标签
Content:里边包裹的若干属性
标准的写法:
width:视口的宽度可以,设置特殊值device-width宽度是设备的宽度
initial-scale:初始化缩放倍数 一般是大于0数字
user-scalable:是否允许用户自行缩放,取值0或1,yes或no
maximum-scale:最大缩放(一般是大于0数字)允许放大的倍数
minimum-scale:最小缩放(一般是大于0数字)允许缩小的最大倍数
二倍图
物理像素点指的是屏幕显示的最小颗粒,是物理真实存在的。 这是厂商在出场时就设置好了(也就是我们的分辨率),
我们开发时候的1px不一定等于一个物理像素
PC端页面 1个px等于一个物理像素 但是移动端就不一样
一个px能显示的物理像素点的个数 称为物理像素比或屏幕像素比
对于一张 50px * 50px 的图片,在手机Retina(视网膜)屏中打开 按照原本的物理像素比会放大倍速 这样会造成图片模糊在标准的viewport设置中 使用倍图来提高图片质量 解决在高清设备中的模糊问题一般都是使用二倍图 ,但因为手机屏幕的影响 现在还存在三倍四倍图的情况背景图片注意缩放
移动端开发的选择
1.单独制作移动端页面(主流)
流式布局(也就是百分比布局)
Flex布局(推荐)
rem适配布局
混合布局(我们日常的布局方式就叫混合布局)
rem单位 rem(root em)是一个相对单位,类似于em,em是父元素字体大小。不同的是rem的基准是相对与html元素的字体大小。比如,根元素(html)设置font-size=12px;非根元素设置width:2rem;则会换成px表示就是24px。优势:可以通过修改html里面的文字大小来改变页面中元素大小,可以整体控制。rem是html与单个元素的比例单位,em是父元素与子元素的比例单位。
* rem的适配方案
<1>.媒体查询+rem方案
<2>.rem.js+rem
(媒体查询限制CSS样式的范围,以便于在满足某些媒体条件时才适用。简单来说:媒体查询可以让我们根据设备显示器的特性(如视口宽度、屏幕比例、设备方向:横向或纵向)为其设定CSS样式。
)
* 它都有那些媒体类型
All(所有设备)
Print(打印设备)
Screen(电脑,笔记本,手机等设备)
* 它都有那些媒体特性
width 网页显示区域完全等于设置的宽度
height 网页显示区域完全等于设置的高度
max-width / max-height 网页显示区域小于等于设置的宽度
min-width / min-width 网页显示区域大于等于设置的宽度
orientation: portrait (竖屏模式) | landscape (横屏模式)
* 语法关键字,将媒体特性与媒体类型链接到一块进行设备检测
and 可以将多个媒体特性链接到一块,相当于且
not 排除某个媒体特性 相当于非,可以省略
only 指定某个特定的媒体类型, 可以省略
* 媒体查询有两种语法
外联语法:
内嵌式语法:
@media screen and (min-width:320px){
html{
font-size: 21.33px;
}
}
* 外联语法:
* 内嵌语法:
@media screen and (min-width:320px){
body {
background:#000;
}
}
@media screen and (min-width:750px){
body{
background:#f99;
}
}
2制作响应式页面兼容移动端(其次)
就是通过媒体查询 限制屏幕的宽度 然后根据不同的宽度写不同的代码
移动端PC端转换
if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android| Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS |Symbian|Windows Phone)/i))) {
// window.location.href = ""; //手机
} else {
window.location.href = ""; //电脑
}
/*pc 移动都添加到scipt标签中(位置在body下面)*/
// 摘要:控制不同尺寸屏幕上的rem基准单位
// 以iPhone6位基准 375px 最大适配750px 屏幕
var maxAdaptation = 750
document.addEventListener('DOMContentLoaded', function () {
var deviceWidth = document.documentElement.clientWidth > maxAdaptation ? maxAdaptation : document.documentElement.clientWidth
document.documentElement.style.fontSize = (deviceWidth / 15) + 'px'
var funID
window.onresize = function () {
clearTimeout(funID)
funID = setTimeout(function () {
var deviceW = document.documentElement.clientWidth > maxAdaptation ? maxAdaptation : document.documentElement.clientWidth
document.documentElement.style.fontSize = (deviceW / 15) + 'px'
}, 500)
}
}, false)
/*只添加在移动端*/
添加下划线的方法
1.元素名::after{
content:'';
height:2px;
background-color:black;
display:block;
}
2.div{
border-bottom:宽度 样式 颜色;
}
以下属性使用时必须配合定位
使用动画时配合相对定位
z-index;调整显示优先级时必须使用定位
JS
JS基本知识
一个完整的javascript实现应该有三个部分构成:ECMAScript、DOM、BOM
javascript特点:1.解释型语言(不进行编译,不用转换成二进制的计算机语言)2.动态型语言(是一类在运行时可以改变其结构的语言)
JS能够做什么:
能改变页面中的所有 HTML 元素
能改变页面中的所有 HTML 属性
能改变页面中的所有 CSS 样式
能删除已有的 HTML 元素和属性
能添加新的 HTML 元素和属性
能对页面中所有已有的 HTML 事件作出反应
能在页面中创建新的 HTML 事件
JS外部引入
1、引入
2、脚本可被放置与 HTML 页面的 或 部分中,或兼而有之。
3、把脚本置于 元素的底部,可改善显示速度,因为脚本编译会拖慢显示。
变量
声明变量: var name ;
var 是一个js关键字,用来声明变量的,使用var关键字声明变量后,计算机会自动为变量分配内存空间,不需要程序员管理
JS输出方式
Js的输出方式:
alert(msg):弹出框
console.log(msg):打印日志(consol方法不止一个)
prompt(msg):输入框 注意:输入类型为字符串
例:输入班级人数与每个人分数求和
var a = prompt('请输入班级总人数')
var sum = 0
for(var i = 1;i<=a;i++){
var b = Number( prompt ('请输入第' + i + '位同学的分数'))//进行强制类型转换将输入的字符串转换为Number
sum = sum + b
}
console.log(sum)
基本数据类型
JS 把数据类型分为两类:
简单数据类型 (Number String Boolean Undefined Null)
复杂数据类型 (数组、object、function...)//数组属于object(对象)
三种对象类型:
对象(Object)\ 日期(Date)\ 数组(Array)
* Number 数字型,包含整型和浮点型值 默认值:0
* Boolean 布尔值类型,true\false 等价于1\0
* String 字符串类型 注意:在JS中,字符串都带有引号
* Undefined 声明变量但是没有给变量赋值,此时 变量=undefined
* Null 声明变量为空值
简单数据类型
数字型范围:
* 最大值:Number.MAX_VALUE,这个值为: 1.7976931348623157e+308
* 最小值:Number.MIN_VALUE,这个值为:5e-324
三个特殊值:
* Infinity ,代表无穷大,大于任何数值
* -Infinity ,代表无穷小,小于任何数值
* NaN ,Not a number,是计算机科学中数值数据类型的一类值,表示未定义或不可表示的值。常在浮点数运算中出现
字符串型 String
var a = '我是帅哥'
var a = "我是帅哥"
注意:因为 HTML 标签里面的属性使用的是双引号,JS 这里我们更推荐使用单引号
JS 可以用单引号嵌套双引号 ,或者用双引号嵌套单引号 (外双内单,外单内双)不能单双引号搭配
Undefined
声明后没有被赋值的变量会有一个默认值 undefined ( 如果进行相连或者相加时,注意结果)
例:
var a;
console.log(a); // undefined
console.log('你好' + a); // 你好undefined
console.log(11 + a); // NaN
NaN console.log(true + a); // NaN
null
一个声明变量给 null 值,里面存的值为空
例:
var q = null;
console.log('你好' + q); // 你好null
console.log(11 + q); // 11
console.log(true + q); // 1
转义符:
\n 换行
\ 代码中换行使用(在行尾添加)
\' 单引号
\" 双引号
\t tab缩进
\b 空格
字符串长度
通过字符串的 .length 属性可以获取整个字符 串的长度
var a = '我他妈是帅哥'
alert(a.length)
输出值为6
字符串拼接
中间必须有+ 变量不加引号(添加引号变字符串)
字面量
字面量是在源代码中一个固定值的表示法,通俗来说,就是字面量表示如何表达这个值。
var a = 1;//这里的1就是字面量
typeof ( ) 方法
获取检测变量的数据类型 ******属于运算符
typeof 可用来获取检测变量的数据类型
例:
var n = 18;
console.log(typeof n) // 结果 number
不同类型的返回值:
typeof 运算符把类型信息当作字符串返回。
* 他有两种用法
1.typeof 变量名
2.Typeof(表达式)
typeof 返回值有六种可能: "number," "string," "boolean," "object," "function," 和 "undefined“
但是我们还有中基本数据类型 null 它的typeof null 的结果是object 历史遗留问题,这是它底层的一个bug
类型转换
转换为字符串类型
三种办法
toString() // var a=1; a.toString()
String()强制转换 // var a=1;String( a )
加号拼接字符串 //var a=1; a+=‘我是字符串’
toString() 和 String() 使用方式不一样。 toString(): 无法转换null和undefined
三种转换方式,我们经常用第三种加号拼接字符串转换方式, 这一种方式也称之为隐式转换。
转换成数字型
parseInt(‘78’)将字符串准换成整数数值型
parseFloat(‘7.21’)将字符串准换成浮点数数值型
Number(‘78’)将字符串准换成数值型(强制转换)
‘12’-0(隐式转换)
注意 parseInt 和 parseFloat 单词的大小写,这2个是重点
隐式转换是我们在进行算数运算的时候,JS 自动转换了数据类型
转换为布尔型
转换的方法 Boolean(‘你好’)
代表空、否定的值会被转换为 false ,如 ''、0、NaN、null、undefined
其余值都会被转换为 true
隐式类型转换存在那些地方(隐式转换的规则)
1. 转成string类型: +(字符串连接符)
2. 转成number类型:++/--(自增自减运算符) - * / % (算术运算符) > ,< ,>= ,<= ,== , != ,=== , !== (关系运算符)
3. 转成boolean类型:!(逻辑非运算符)
其他注意事项:
标识符 标识符:就是指开发人员为变量、属性、函数、参数取的名字。 标识符不能是关键字或保留字。
关键字:是指 JS本身已经使用了的字,不能再用它们充当变量名、方法名。例如:break、case、catch、continue、default、delete、do、else、finally、for、function、if、in、 instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with 等
保留字 保留字:实际上就是预留的“关键字”,意思是现在虽然还不是关键字,但是未来可能会成为关键字,同样不 能使用它们当变量名或方法名。例如:boolean、byte、char、class、const、debugger、double、enum、export、extends、 fimal、float、goto、implements、import、int、interface、long、mative、package、 private、protected、public、short、static、super、synchronized、throws、transient、 volatile 等
运算符
算数运算符
递增和递减运算符
比较运算符
逻辑运算符
赋值运算符
NaN 与任何值进行运算结果都为NaN
+有一种特殊情况,当字符串与其他数据类型进行+运算时,会进行字符串拼接
浮点数精度问题
var result = 0.1 + 0.2; // 结果不是 0.3,而是:0.30000000000000004
console.log(0.07 * 100); // 结果不是 7, 而是:7.000000000000001
所以:不要直接判断两个浮点数是否相等 !
++a 不能单独打印,会先运行打印a 再自增。
a++ => 返回的值是a本身
++a => 返回的值是a+1后的值
开发时,大多使用后置递增/减,并且代码独占一行,例如:num++; 或者 num--;
全等运算符 === 要求值和数值类型都一致
区别:
= 赋值 右边值给左边
== 判断 判断两边值是否相等(注意此时有隐式转换)
=== 全等 判断两边值与数据类型均相等
逻辑运算符
&& 与 || 或 ! 非
逻辑非 ! :也叫作取反符,用来取一个布尔值相反的值,如 true 的相反值是 false(返回值为布尔类型,自然数为true,其余均为false)
运算符优先级:
一元运算符中逻辑非优先级最高
逻辑与比逻辑或优先级高
字符串拼接
var a = ''
for(var i = 1 ;i<=9 ;i++){
for(var j = 1; j<=i ; j++){
a = a + j + '*' + i + '=' + i*j + '\t' //字符串拼接
}
a += '\n' //字符串拼接
}
console.log(a)
九*九 乘法表
注意字符串拼接方法
拼接后a变量中存放的均为字符串:1*1=2\t\n2*2=4....
字符串部分方法
length长度属性
查找字符串
indexOf () 方法返回字符串中指定文本首次出现的索引(位置): 传入两个值,(第一要查找的目标,起始位置)
lastIndexOf()
如果未找到文本, indexOf() 和 lastIndexOf() 均返回 -1。 传入两个值,(第一要查找的目标,起始位置)
search() 方法搜索特定值的字符串,并返回匹配的位置
search() 方法无法设置第二个开始位置参数。
indexOf() 方法无法设置更强大的搜索值(正则表达式)。
提取部分字符串
slice () 切割字符串 该方法设置两个参数:起始索引(开始位置),终止索引(结束位置)。 不包含结束索引 掺传入负值为反着拿值
substring() 切割字符串 该方法设置两个参数:起始索引(开始位置),终止索引(结束位置)。 不包含结束索引 不可传入负值
substr() 切割字符串 该方法设置两个参数:起始索引(开始位置),截取字符串长度。 不包含结束索引
替换字符串
replace (‘传入要被替换的值’,‘要更换的新值’)
toUpperCase() 字符串转换为大写:
toLowerCase() 字符串转换为小写:
concat() 连接两个或多个字符串:
trim() 方法删除字符串两端的空白符
charAt() 方法返回字符串中指定下标(位置)的字符串:
charCodeAt() 方法返回字符串中指定索引的字符 unicode 编码:
split () 将字符串转换为数组:
toLocaleUpperCase () 字符串转换为大写:
toLocaleLowerCase () 字符串转换为小写:
循环
断点调试
浏览器打开页面 → 按f12打开开发者工具 → 打开Sources → 打开你要调试的js代码文件 → 在想查看的地方的行号上单击一下→在刷新页面 → f11
watch:监视,通过watch可以监视变量的值的变化
F11:程序单步执行,也就是一行一行的执行,这个时候,观察watch中变量值的变化
很总要,学会调试也就获得了查找bug的能力
for循环
for循环语法
for(初始化变量; 条件表达式; 操作表达式 ){//条件表达式为true,会一直执行
循环体
}
for(表达式1){
for(表达式2){
}
}
While循环
While(表达式){ //满足条件进入循环,当值为true时为死循环,false时终止循环/break打断循环
}
//先判断再循环
创建一个whlie循环也需要3个步骤
1.初始化一个变量 (只执行一次)
var a = 0;
2.在循环体中设置一个条件表达式
while(a > 10){
3.定义一个更新表达式
a++
循环体执行一次a变量更新一次,
}
do...while循环
do{
语句
}while(条件表达式){
语句
}
//两者执行的流程不同do..while语句在执行时,先执行循环体,后判断
//能保证这个循环体至少执行一次
// !!!注意:while条件表达式中值为true时循环,值为false时结束循环.条件为真的话,就会重复这个循环
//陷入无限循环的两个条件:
// 1.条件判断始终为true
// 2.使用变量作为条件,未设置在循环中自然增长,则会出现无限循环
switch..case 循环
switch (表达式){
case value1:
statements1 // 当表达式的结果等于 value1 时,则执行该代码
break;
case value2:
statements2 // 当表达式的结果等于 value2 时,则执行该代码
break;
......
case valueN:
statementsN // 当表达式的结果等于 valueN 时,则执行该代码
break;
default :
statements // 如果没有与表达式相同的值,则执行该代码
}
//注意:switch 语句中,表达式是使用全等(===)来与各个 cese 子句中的值进行匹配的。由于使用的是全等运算符,因此不会自动转换每个值的类型。
跳出循环
break 语句“跳出”循环。直接跳出不再执行后边的循环
continue 语句“跳过”循环中的一个迭代。后边的循环继续执行
数组 Array
创建数组的两种方式:
1.利用 new 创建数组
2.利用数组字面量创建数组(常用) // var 数组名 = []
通过new关键字创建数组:
var 数组名 = new Array() //Array 严格区分大小写
数组中可以存放任意类型的数据
可以利用循环来遍历数组
数组名.length //访问数组长度
//注意!!!当两个数组进行传值的时候用slice()方法可以避免'指针'问题
数组的常用方法
数组中的常用四种方法:
1.向数组的最后一位添加一个或者多个新的元素,并反回长度
push方法
数组.push()
2.pop方法
可以删除数组的最后一位并返回
数组.pop()
3.unshift方法
可以向数组第一位添加一个或多个新的元素,并返回长度
数组.unshift()
4.shift方法
可以删除数组中第一位,并返回
数组.shift()
5.splice方法//删除/插入
可以删除数组中的某一位
数组.splice//(第几位,删除几个值)
数组.splice(2,0,'abc')//在第二位,删除0个值,插入abc
6.slice方法//复制数组的一部分,!!!用slice方法复制的新数组可以避免'指针'的问题
返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象
举例:var n =[0,1,2,3,4,5,6,7,8,9]
var a = n.slice(2,5)
console.log(a)//a数组为[2,3,4]
7.concat()方法//拼接数组
拼接两个数组
举例:
var arr = [1,1,1]
var arry = [2,2,2]
ar = arr.concat(arry)//ar数组为[1,1,1,2,2,2]
8.join()方法//变为字符串
把数组中的所有元素放入一个字符串,元素是通过指定的分隔符进行分隔的//注意:返回值为字符串
举例:
var x = [1,1,1]
var y = x.join()//括号内为分隔符,默认为 ,
9.reverse()方法//改变原数组,颠倒顺序
可以颠倒数组中元素的顺序
var n = [1,2,3]
n.reverse()//数组变为[3,2,1]
10.sort()方法//数组从小到大顺序排序(注意:根据UTF-16代码单元值进行排序,只能排序十以内的数字)
* 用于确定传递的值是否是一个 Array(判断它是不是个数组) 返回false或者true
Array.isArray(表达式/变量)
将伪数组转化为标准数组
Array.prototype.slice.call(伪数组名)
普通排序与冒泡排序
***//举例:数组去重
var n = [1, 2, 3, 4, 5, 6, 7, 8, 9, 5, 3, 1, 5, 6, 7, 3, 3, 3]
for(var i = 0 ;i< n.length; i++){
for(var j = i+1 ; j n[j+1]){//比较相邻两数大小,如果后值较大,交换相邻两数位置
var k = ''
k = n[j+1]
n[j+1] = n[j]
n[j] = k
}
}
//数组排序
}
console.log(n)
***//普通排序
var arr = [5, 7, 9, 6, 3, 4, 2, 1, 8]
for (var i = 0; i < arr.length - 1; i++) {//j为i+1,省去一次循环步骤
for (var j = i + 1; j < arr.length; j++) {//在内循环中,i始终没变,相当于前面的数与后面每一个比较
if (arr[i] > arr[j]) {//当前下标为i的值与当前下标为j的进行比较,如果大于就准换位置
sun = arr[i]//第三方变量存储值并更换值
arr[i] = arr[j]
arr[j] = sun
}
}
}
console.log(arr)
对象 Object
在JS中,对象是一组无序的相关属性和方法的集合。//对象是由属性和方法组成的
创建对象的三种方法
1. var 对象名 = new Object() //严格区分大小写
2. var 对象名 = {}
3.构造函数
对象的调用
1.对象名.name//取值,调用(仅返回值)
2.对象名[‘name’] //取值,调用(仅返回值)
给对象插入属性
注意,对象中每条属性用 , 隔开
1.对象名.属性名 = '属性值' //属性值为字符串时要加 ''
举例:
ls.name = '李硕', //每加一条属性后要加 ,
2. var ls{}
ls.name = 'lishuo',
var a = 'age' //创建一个变量值为属性名(必须为字符串)
ls[a] = 18 //添加属性 age = 18
遍历对象的方法
entries()
Object.entries() 方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)
var obj = {
name:'lishuo',
age:22
}
console.log(Object.entries(obj))
// ['name', 'lishuo']
// ['age', 22]
//返回为数组
var obj = {
name: 'lishuo',
age: 22
}
for (const [key, value] of Object.entries(obj)) {
console.log(`${key}: ${value}`);
}
// name: lishuo
// age: 22
//返回为字符串
冻结对象和属性
var constantize = (obj) => {
Object.freeze(obj);//冻结对象
Object.keys(obj).forEach( (key, i) => {//冻结对象内的属性
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};
函数 Function
在开发过程中,部分代码会被重复使用,函数可把代码封装起来重复使用
函数语法:
function 函数名(形参){
代码段
}
调用:函数名(实参)
如果实参个数多于形参,形参将按照顺序依次接收实参,剩余的值不被接收
如果实参个数少于形参,形参将按照顺序依次接收实参,多于的形参接收不到实参,默认值为undefined
//函数中的return语句的两个作用:
1.函数中通过return关键字指定返回值
2.结束当前函数,不在继续向下执行代码//注意:return后的语句不再执行
3.如果没有指定返回值,则函数默认返回值为undefined
arguments 对象
//函数中的arguments对象:(它的行为就像数组)
当不确定有多少个参数传递的时候,可以用arguments来获取,在js中,arguments实际上它是当前函数的一个内置对象,所有的函数都有一个内置的arguments对象,arguments对象中储存了传递的所有实参//(当实参是否大于形参,实参都会储存在arguments中)
//arguments对象特点:
1.arguments的展示形式是一个伪数组,具有数组的特点,但是不可以使用数组的方法,因此可以进行遍历
2.伪数组的特点(数组的特点)
具有length属性
按照索引方式存储数据
不具有数组的push,pop等方法
局部变量与全局变量
在函数内部声明的变量叫做局部变量,在函数外部的变量叫做全局变量
变量提升:将局部变量该变为全局变量//提升方法:在函数中声明新变量时不使用var 直接使用变量
当js执行的时候,发现你的字段未被声明,js会向顶端自动补充声明
作用域:
* 全局作用域:整个script标签或是某一个单独的js文件
* 局部作用域:在函数内部的就是局部作用域,这个代码或者名字只能在函数内部起效果和作用
作用域链:
* 在某个作用域中访问某个变量时,如果当前作用域中没有该变量,则会依次向上访问上层的作用域的变量
try...catch
try...catch 捕捉到错误后仍可继续运行
构造函数
构造函数通俗含义:对象的创造工厂//通常函数名首字母都会大写
构造函数与普通函数的区别在于构造函数有 this
this 只在 new 时使用
例:
function Man(a,b,c){
this.name = a; //this 指向新定义的变量空间(this 指向 变量lishuo 的空间,为 lishuo 添加属性)
this.age = b;//实例成员
this.sex = c;
this.fn = function(){//复杂类型(所有实例化成员中都会有fn方法,需要被调用才会执行)
//注意:这样的方法只是他自己的方法,不可以继承
console.log('敲代码')//注意:虽然实例化成员调用函数都会输出'敲代码',但是对象间的'敲代码并不相同'
}
}
var lishuo = new Man('李硕',18,'男') //变量lishuo 中储存了一个对象,也可以说 变量lishuo就是一个对象。 new的返回值为对象,所以构造函数不需要return
Man.height = '60' //静态成员,是添加给Man的属性,不影响实例化成员
new 在执行时会做四件事情:
(1)在内存中创建了一个新对象。
(2)让this指向这个新的对象
(3)通过执行构造函数里边的代码,给这个新对象添加属性和方法。
(4)返回这个新对象(所以构造函数不需要return)
构造函数
构造函数中可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数内部的 this 上添加,通过这两种方式添加的成员,就分别称为静态成员和实例成员。
//静态成员与实例成员只影响构造函数
静态成员:在构造函数本身添加的成员叫做静态成员。静态成员只能通过构造函数进行访问,不能通过对象访问。
实例成员:在构造函数内部通过this添加的成员叫做实例成员。实例成员只能通过实例化对象进行访问,不可以通过构造函数访问
//实例化对象只能调用实例成员
//构造函数只能调用静态成员
构造函数的原型对象 prototype
构造函数通过原型分配的函数是所有对象的共享的// !!! prototype是一个对象
每一个构造函数都有一个prototype属性,指向另一个对象(构造函数下面的对象),注意这个 prototype 就是一个对象,这个对象的所有属性和方法都会被构造函数所拥有(可以被构造函数下的实例化对象拥有)
可以把一些不变的方法,直接定义在prototype对象上,这样所有的实例化对象可以共享这些方法了
//prototype 也是构造函数中的一个实例成员
举例:
function Man(name,sex,age){ //构造函数
this.name = name//实例成员
this.age = age
this.sex = sex
}
//原型对象 prototype
Man.prototype = {
fn1:function(){
console.log('敲代码')
},
height:180,
fn2:function(){
console.log('吃饭')
},
fn3:function(){
console.log('打豆豆')
},
constructor:Man //
}
//Man.prototype.weight = '70kg'
//给prototype添加的属性,实例化对象都会继承
var xz = new Man('小猪','男',18)
var kk = new Man('康康','男',20)
var jj = new Man('静静','女',2)
xz.fn4()
jj.fn1()
实例化对象的 proto 属性
* 实例化对象 身上的 _proto_属性,指向公共的prototype
* 对象身上系统自动添加了一个_proto_指向了 构造函数的prototype原型对象
查找规则:首先看实例化对象身上有没有这个属性(实例化对象单独添加的),如果有就执行这个属性,如果没有就通过_proto_属性去查找构造函数的原型对象(prototype)有没有这个属性
实例化对象.__proto__ === 构造函数.prototype
在 原型对象(prtotype) 和 对象原型 (proto) 中的constructor
constructor 属性返回所有 JavaScript 变量的构造器函数
* 在原型对象中和对象原型中的constructor属性指向生成他们的构造函数(在prototype对象中)
* 但是原型对象被修改覆盖后constructor就被覆盖了,我们也就不知道他构造函数是谁了,所以在覆盖的时候我们重新创建一个constructor并让他指向了自己的构造函数
在覆盖的prototype对象中加入 constructor:构造函数
总结
__proto__\prototype\constructor\new\this
constructor 在prototype(原型对象)里面,指向构造函数的
prototype 是构造函数中给实例化对象公共的继承对象
this 指向实例化对象空间
new 指向构造函数
__proto__ 在实例化对象中指向prototype(原型对象)
对象由函数生成
对象有__proto__属性,函数有prototype属性
生成对象时,对象的__proto__属性指向函数的prototype属性
Math对象
Math 不是构造函数。Math 的所有属性/方法都可以通过使用 Math 作为对象来调用,而无需创建它
Math.abs() 求绝对值
Math.max() 求最大值
Math.min() 求最小值
Math.ceil() 函数返回大于或等于一个给定数字的最小整数(向上取整)
Math.floor()可以理解为向下取整
Math.random()打印大于等于0且小于1的随机数
Math.round(3.1415926)四舍五入
Math.trunc() 返回数字的整数部分
Math.cbrt(x) 返回 x 的三次方根
Math.sign(x) 返回数的符号(检查它是正数、负数还是零)
Math.random() 返回0-1之间的随机数
// function fn (a1,a2){
// for(var i = 0;i<100 ; i++){
// var num = Math.floor( Math.random()*(a2-a1+1)+a1 )
// console.log(num)
// }
// }
// fn( 5,10 ) 求100个 a1 到 a2 之间的随机数 (包含a1、a2)
Date 对象
日期对象是用 new Date() 创建的
日期对象是静态的。计算机时间正在滴答作响,但日期对象不会
将日期存储为自 1970 年 1 月 1 日 00:00:00 UTC(协调世界时)以来的毫秒数
实例化日期有四种方式:
var d = new Date();
var d = new Date(milliseconds);//毫秒
var d = new Date(dateString);//日期字符串,日期中间用分隔符连接,月份日期为单数时前面加0 ,02月
var d = new Date(year, month, day, hours, minutes, seconds, milliseconds);
//注意:月份、星期等 计算从0月、星期0开始
// 例:
// var d = new Date(2018, 11, 24, 10, 33, 30, 0);
// 7个数字分别指定年、月、日、小时、分钟、秒和毫秒(按此顺序)
//6个数字指定年、月、日、小时、分钟、秒 以此类推 2个数字指定年份和月份 但是不能只提供一个参数,不然会被视为毫秒
日期获取方法://var a =
getDate() 以数值返回天(1-31)
getDay() 以数值获取周名(0-6)
getFullYear() 获取四位的年(yyyy)
getHours() 获取小时(0-23)
getMilliseconds() 获取毫秒(0-999)
getMinutes() 获取分(0-59)
getMonth() 获取月(0-11)
getSeconds() 获取秒(0-59)
getTime() 获取时间(从 1970 年 1 月 1 日至今)
日期获得方法://var a =
setDate() 以数值(1-31)设置日
setFullYear() 设置年(可选月和日)
setHours() 设置小时(0-23)
setMilliseconds() 设置毫秒(0-999)
setMinutes() 设置分(0-59)
setMonth() 设置月(0-11)
setSeconds() 设置秒(0-59)
setTime() 设置时间(从 1970 年 1 月 1 日至今的毫秒数)
/* 例:
var date = new Date()
var a = date.getFullYear() //获取四位的年(yyyy)
console.log(a) */
/* 例:
var endtime = new Date("2021/11/11");//定义结束时间标准时间
var setitem = new Date()//获取当前的标准时间
// 获取时间戳 getTime() 单位毫秒
var item = endtime.getTime() - setitem.getTime()
leftd = Math.floor(item/(1000*60*60*24)), //计算天数
lefth = Math.floor(item/(1000*60*60)%24), //计算小时数
leftm = Math.floor(item/(1000*60)%60), //计算分钟数
lefts = Math.floor(item/1000%60); //计算秒数
var a = leftd + "天" + lefth + '小时' + + leftm + "分钟" + lefts + '秒'; //返回倒计时的字符串
console.log(a) */
计时器
setInterval():按照指定的周期(以毫秒计)来调用函数或计算表达式。方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。
注意:一般计时器用完后需要关闭计时器 clearInterval ( 计时器名 )
关闭计时器后最好再清空计时器
item = setInterval ( , ) //设置计时器
clearInterval ( item ) //关闭计时器
item = null //清空计时器
格式:setInterval ( 重复操作 , 间隔时间 )
计时器为window对象下的
var a = 1
var fn = null
var fn = setInterval(function(){//执行方法
console.log(10)
a++
if(a == 10){
clearInterval(fn)
}
},1000)//间隔1s
//计时器中重复操作不能调用函数,写函数变量名(变量内存中储存着函数操作)
//计时器创建前先初始化计时器
例:
left.onclick =zd //不能写 = 函数名() 函数变量名内就存储着函数内容
var x = 0
function zd() {
x++
if (x == img_.length) {
x = 0
}
img.src = img_[x]
// console.log(x)
}
setInterval(zd,1000)//计时器重复操作写函数变量名
setTimeout():在指定的毫秒数后调用函数或计算表达式。在指定的时间之后执行一次
setTimeout(function(){//执行方法
console.log(10)
},3000)//间隔三秒
call()方法
它可以用来调用所有者对象作为参数的方法。
通过 call(),您能够使用属于另一个对象的方法
call ( obj,参数列表 ) call方法传入两个参数,第一个为对象(必写)。若没有对象传入,写法为 call( null , 参数列表 )
var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var person2 = {
firstName:"Steve",
lastName: "Jobs"
}
var x = person.fullName.call(person2); //调用fullName,传入的参数为person2
console.log(x);//Steve Jobs
apply()方法
apply() 方法与 call() 方法非常相似
同样必须传入两个参数 apply ( obj , 参数数组 ) 若只传数组,则写法为:apply ( null , array )
不同之处是: call() 方法分别接受参数。 apply() 方法接受数组形式的参数。 如果要使用数组而不是参数列表,则 apply() 方法非常方便
var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var x = person.fullName.apply(person1);
console.log(x);//Bill Gates
//apply() 方法接受数组中的参数
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var x = person.fullName.apply(person1, ["Seatle", "USA"]); //apply()用数组传递参数
console.log(x);//Bill Gates,Seatle,USA
//call()方法不用数组传递参数
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var person2 = {
firstName:"Steve",
lastName: "Jobs"
}
var x = person.fullName.call(person1, "Seatle", "USA"); //call()不用数组传递参数
console.log(x);//Bill Gates,Seatle,USA
Dom 事件
全称:文档对象模型(Document Object Model,简称DOM )
根元素 上级为文档
通过这个对象模型,JavaScript 获得创建动态 HTML 的所有力量
能改变页面中的所有 HTML 元素
能改变页面中的所有 HTML 属性
能改变页面中的所有 CSS 样式
能删除已有的 HTML 元素和属性
能添加新的 HTML 元素和属性
能对页面中所有已有的 HTML 事件作出反应
能在页面中创建新的 HTML 事件
在 HTML DOM (Document Object Model) 中 , 每一个元素都是 节点
在节点树中,顶端节点被称为根节点
每个节点都有父节点、除了根(它没有父节点)
节点没有父节点;它是根节点
和 的父节点是 节点
文本节点 "Hello world!" 的父节点是 节点
Dom 对象 - 方法和属性
DOM 方法 是我们可以在节点(HTML 元素)上执行的动作。
DOM 属性 是我们可以在节点(HTML 元素)设置和修改的值。
属性是您能够获取或设置的值(就比如改变 HTML 元素的内容)。
方法是您能够完成的动作(比如添加或删除 HTML 元素)。
节点(Node)
节点属性是节点(HTML 元素)的值,能够获取或设置
* Node
innerHTML 获取/设置/改变一个元素的标签和开始标签与结束标签之间的内容(所有元素内的内容都会识别,包括子元素标签等)(建议使用)
innerText 也可以获取元素内的内容,但是innerText不识别换行空格等,只识别文本(一般不建议使用)
className 获取/设置一个元素的class属性的属性值
value 获取/设置一个元素的value属性
parentNode 获取一个元素的父级元素
children 获取该元素的子元素集合//元素
事件
本质:Node节点下的方法
onclick 单击事件//(通过更改class name 切换为另一个css样式)
onmouseover 鼠标移上事件
onmouseout 鼠标离开事件
//给伪数组添加事件时必须添加到具体元素,因为伪数组也为对象,添加方法相当于给对象添加了属性(遍历添加)
两种绑定方式
1、 点我 //将按钮绑定单击事件,单击执行方法
function displayDate(){ //设置单击方法
alert('11')
}
2、document.getElementById("myBtn").οnclick=function(){alert(11)}; //获得按钮节点.绑定单击事件 = 方法
//选项卡 方法1:通过JS更改样式 方法2:通过JS更改类名,对应要改变的样式
var head = document.getElementsByClassName('sj')
for (var i = 0; i < head.length; i++) {
/ head[i].number = i///注意赋下标(在排他中用到)
head[i].onclick = function(){
for (var j = 0; j < head.length; j++) {
head[j].style.background = 'blue'//排他思想,点击后所有背景都为蓝色
}
this.style.background = 'red'//this指向调用的这个div,改为红色
}
}//实现选项卡功能,点击哪个哪个变色,点击其他的,之前点击的颜色变回初始颜色
获取节点方法
如何获取我们的节点
document == 网页文档(访问 HTML 页面中的任何元素,那么您总是从访问 document 对象开始)
getElementById() 返回一个与id值相匹配的Node节点
getElementsByClassName() 返回一个与类名相匹配的NodeList(类数组)//注意:返回值为伪数组,获取元素时需要遍历
getElementsByTagName() 返回一个与标签名相匹配的NodeList(类数组)//注意:返回值为伪数组,获取元素时需要遍历
document.querySelector()获取指定选择器元素集合的第一个元素节点//返回一个节点
document.querySelectorAall() 获取指定选择器的所有元素集合//返回节点集合
querySelector与getElement 的区别:前者获取内容的为静态的(获取内容不随着文档变化),后者获取的内容为动态的(随着文档改变内容改变)//但是前者===后者,是因为JS底层逻辑规定的
// .cheildren 获取子元素集合 只能识别元素
//找节点也可以通过父节点里面的标签方法、 .children方法、 .parentNode方法(.document只用写一次)
动态创建获取添加删除节点方法
一般的,节点至少拥有nodeType(节点类型),nodeName(节点明称),和nodeValue(节点值)这三个基本属性
元素节点nodeType为1
属性节点nodeType为2
文本节点nodeType为3,文字,空格,换行等
获取子节点:节点.childNodes (标准) 一般不使用(兼容性问题)
返回指定节点的子节点的集合,该节点位及时更新的集合(包括注释,文本,元素都会返回)
返回节点下所有子元素节点,其他不返回(只返回元素)
获取 第一个元素 子节点:节点.firstElementChild (IE9以上浏览器支持)
获取 最后一个元素 子节点:节点.lastElementChild (IE9以上浏览器支持)
获取 当前元素节点的下一个兄弟节点:当前节点.nextElementSibling (没有则返回null)(兼容性IE9以上)
获取 当前元素节点的上一个兄弟节点:当前节点.previousElementSibling (没有则返回null)(兼容性IE9以上)
动态创建元素节点: document.createElement('tagName') //标签名
(.innerHTML也能创建元素节点 )
通过不同思路使用不同的创捷节点方法(考虑时间优化问题)
var a = document.createElement('div')
动态添加节点 :
父级节点.appendChild( ' 子节点 ' ) 添加在父节点列表末尾
var a = document.createElement('div')
a.innerHTML = 'haizi5'
a.className = 'ppp'//添加属性还是用JS原本添加属性的方法
father.appendChild(a)
父节点.insertBefore(子节点) 添加在父节点列表任意位置 (括号内添加两个参数) ( 添加节点名 , 添加在哪个子元素节点前 )
var father = document.getElementsByClassName('father')[0]//获取父元素
var a = document.createElement('div')//动态创建子元素
a.innerHTML = 'haizi5'
father.insertBefore(a,father.children[2])//将子元素插入在父元素中,插入位置为第3个子元素前
给页面动态添加一个元素话需要3步奏
1.创建一个节点
2.找到父级节点
3.将元素插入父级节点
删除节点:
node.removeChild(节点) 删除选中节点
父节点名.removeChild(要删除的子节点名)
//获取: //没加Element获取的子节点都包含注释节点等
.childNodes (数组) //获取子元素(所有元素,包括文本节点和注释节点)
.parentNode //获取父元素
.chlidren (数组) //获取子元素(返回数组,只返回标签节点)(常用)
.firstElementChild//获取子元素第一个标签节点
.firstChild //获取第一个节点(包括注释节点)
.lastElementChild//获取最后一个标签节点
.nextElementSibling//获取当前标签节点的下一个兄弟标签节点
.previousElementSibling//获取当前标签节点的上一个兄弟标签节点
input 框事件:
onfocus 获取焦点事件
onblur 失去焦点事件
input框获取其中内容不能用innerHTML和innerText 只能用value
鼠标事件
onmousecover
onmouseenter
TAB 选项卡(三种方法)
// var tab_ = document.getElementsByClassName('div4_2_1')//控制
// var tab = document.getElementsByClassName('tab_')//图片
// for(let i = 0;i
自定义属性
定义自定义属性为了与自带属性区分,通常属性前加data- 例:data-num='0'
如何设置自定义属性:
1.直接在标签中设置:例 :
2.在JS中设置: 例: 节点名.setAttribute ( ' 属性名 ' , 属性值 ) //注意区分对象的添加属性和自定义属性
3.在JS中设置:节点名.dataset.属性名 = 属性值 (这种设置方法为默认在属性名前添加data-)可能存在兼容性问题
用自定义方法设置标签自带的属性名,可以覆盖原本的属性
调用自定义属性:1.节点名.getAttribute( ' 自定义属性名 ' )
2.当自定义属性符合H5命名规范后,可以用 节点名.dataset.自定义属性名(不用加data-)来获取 例: 现有自定义属性 data-index = '5'
调用: 节点名.dataset,index
Dom 总结
创建操作:
1.document.write
2.innerHTML
3.createElement
增加操作:
1.appenChild
2.insertBefore
删除操作
removeChild
修改操作
1.修改元素的属性:src,href,title等
2.修改元素的内容:innerHTML,innerText
3.修改表单元素:value,type,disabled
4.修改样式:style,className
查询操作:
1.dom提供的API方法:getElementById,getElementsByTagName古老用法不太推荐
2.H5提供的新方法:querySelector,querySelectorAll提倡
3.利用节点操作获取元素:父(parentNode),子(child),兄(previousElementSibling),nextElementSibling
自定义属性:
1.setAttribute:设置自定义属性
2.getAttribute:得到dom的属性
3.removeAttitude:移出属性
事件操作:
1.onclick:点击事件
2.ondblclci:双击事件
3.onfocus:鼠标移入事件
4.onblur:鼠标移出事件
5.onmouseover:鼠标移上触发
6.onmouseout:鼠标移出触发
BOM对象
BOM就是浏览器窗口对象模型,顶点对象就是window,Bom包含了Dom
JS执行机制
JS执行机制:单线程 JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事
同步和异步
为了解决单线程的这个问题,利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创 建多个线程。于是,JS 中出现了同步和异步
同步任务 :同步任务都在主线程上执行,形成一个执行栈 异步任务 :js 的异步任务事通过回调函数实现的。一般而言,异步任务有以下三种类型:
①普通事件:如 click , resize等
② 资源加载:如 load , error 等
③定时器:包括 setInterval , setTimeout等
异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)
执行顺序: ①先执行执行栈中的同步任务 ②异步任务(回调函数)放入任务队列中 ③一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。 ④由于主线程不断的重复获得任务,执行任务,再获取任务,再执行,所以这种机制被称为“事件循环”(event loop)。
举例:
bt.style.display = 'block' //先设置盒子block
setTimeout(function () { //设置延时器,但是延时时间为0,利用异步,使得Dom加载完再执行延时器
bt.style.opacity = '1' //再设置一个transition:1s; 就有渐显效果
}, 0);
元素偏移量 offset 系列
节点.offsetParent // 返回作为该元素带有定位 的父级元素,如果父级元素都 没有定位则返回body 节点.offsetTop // 返回元素相对带有定位 父元素上方的偏移 节点.offsetLeft // 返回元素相对带有定位 父元素左边框的偏移 节点.offsetWidth // 返回自身包括padding 、边框 、内容区的宽度,返回数值不带单位 节点.offsetHeight // 返回自身包括padding 、边框 、内容区的高度,返回数值不带单位
offset 与 style 的区别 offset style offset可以得到任意样式表中的样式值 style只能得到行内样式表中的样式值(通过CSS写的样式获取不到) offset系列获取的数值没有单位 style获取的是带有单位的字符串 offsetWidth包含padding + border + width style.width获得不包含padding和border offsetWidth等属性是只读属性,只能获取不能赋值 style.width可读写 所以,offset用来获取,style用来更改值
元素可视区 client 系列
client 翻译过来就是客户端,我们使用 client 系列的相关属性来获取元素可视区的相关信息。通过 client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等 element.clientTop 返回元素上边框的大小 element.clientLeft 返回元素左边框的大小 element.clientWidth 返回自身包括padding+内容区的宽度、不含边框,返回数值不带单位。 element.clientHeight 返回自身包括padding+内容区的高度、不含边框,返回数值不带单位。
元素滚动 Scroll 系列
使用 scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等 scrollWidth / scrollHeight内容没有超出元素范围时 scrollWidth = 元素宽度 + 内边距宽度 == clientWidth scrollHeight = 元素高度 + 内边距的高度 == clientHeight 内容超出元素范围时 scrollWidth = 元素宽度 + 内边距宽度 + 超出的宽度 scrollHeight = 元素高度 + 内边距的高度 + 超出的高度 scrollTop / scrollLeft scrollTop 超出元素内边距顶部的距离 scrollLeft 超出元素内边距左边的距离
onscroll 事件
滚动条在滚动时会触发 onscroll 事件 浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动时,页面上面被隐藏 掉的高度,我们就称为页面被卷去的头部 页面被卷去的头部:可以通过window.pageYOffset 获得 如果是被卷去的左侧 window.pageXOffset 例:点击按钮回到页面顶端
document.addEventListener('scroll', function () { // bt 为回到顶端的按钮 创建scroll 事件
if (window.pageYOffset >= 500) { //如果页面被卷去500 (px)
bt.style.display = 'block' // 显示 bt 按钮
setTimeout(function () {
bt.style.opacity = '1' // 利用异步 使得按钮有渐显效果
}, 0);
}else{
bt.style.opacity = '0' //如果页面没有被卷去500 (px)
setTimeout(function () {
bt.style.display = 'none' //隐藏按钮
}, 0);
}
})
bt.onclick = function(){ //给按钮创建单击事件
var item = setInterval(function(){ //创建计时器 每10ms 滚动距离-50 使得页面有逐渐上滚的效果
if(window.pageYOffset > 0){
var Y = window.pageYOffset
Y -= 50
window.scroll(0,Y) // X轴为0 Y轴实时变化
}else{
clearInterval(item) // 当被卷去距离为0时关闭计时器
}
},10)
}
兼容性问题: DTD: (页面头部) 1.声明了 DTD,使用 document.documentElement.scrollTop 2.未声明 DTD,使用 document.body.scrollTop 3.新方法 window.pageYOffset 和 window.pageXOffset,IE9 开始支持
function getScroll() { //解决兼容性问题
return {
left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft||0,
top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0
};
}
调用时 getScroll()
this 指向问题
在普通函数中 this指向了widow对象
Function xx() {
console.Log(this)
}
xx()调用后的这里的 this 指向 widow
call
、apply
和bind
是Function
对象自带的三个方法,这三个方法的主要作用是改变函数中的this
指向
call() 方法和 apply() 方法 作用:改变函数的this指向 相同点: 这两个方法的作用是一样的 不同点: 接收参数的方式不同(根据接收参数情况使用两种方法)
call() 方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。
apply() 方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
bind() 方法 接收的参数与call一样但是调用方式不一样
//方法使用方式:
函数.call(设置指向的对象,参数1,参数2...)//call方法内第一个参数为this的指向方向,后面为函数需要传入的参数(用逗号隔开)
函数.apply(设置指向的对象,[参数1,参数2...])//apply方法第一个参数为this指向的方向,后面函数需要传入的参数以数组的形式写
函数.bind(设置指向的对象,参数1,参数2...)()//
注意:
apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用
克隆
节点.cloneNode ( )
// 值为空或false 为浅拷贝 只复制节点本身,不复制节点内的子节点
// 值为true 为深拷贝 复制节点以及节点内的所有子节点
事件高级
注册事件(绑定事件)
给元素添加事件 ,称为注册事件或者绑定事件, 注册事件 有两种方式:传统方式和方法监听注册方式 两种传统绑定事件方式:
1.
///标签内绑定
function index(){
console.log(1)
}
2.node.οnclick=function(){//JS中绑定
console.log(1)
}
传统事件绑定特点:注册事件的唯一性 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前边注册的处理函数
监听 方法注册方式:addEventListener() 特点:同一个元素同一个事件可以注册多个监听器 按照注册顺序依次执行
传统方式默认只触发冒泡阶段,监听事件可以通过调整参数触发捕获阶段
//写法:
节点名.addEventListener(type,listener,uesCapture)//将监听器注册到目标节点身上,对象触发指定事件时,就会执行处理函数
//该方法的三个参数:
1.type:事件类型;类型字符串,比如click,mouseover,//注意这里没on
2.listener:事件处理函数,事件发生时我们会调用的函数
3.uesCapture:可选参数,是一个布尔值。默认是false,false/true:false为冒泡/ture为捕获,参数是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序//有兼容性问题IE9
//IE9前的事件监听方法:(了解)
//节点.attachEvent(EventNameWithOn,callback)
//EventNameWithOn:事件类型必须加on
//callback:事件处理函数,当目标被触发时执行
删除事件(解除绑定)
删除传统绑定事件:node.onclick = null
删除监听事件的方式: 1.removeEventlistener 节点.removeEventlistener(type,listener,useCapture) (主要) 2.dataEvent 节点.dataEvent(eventNameWithOn,callback) (IE9以下使用)
var btn2=document.getElementById("btn2");/*匿名函数*/
24 btn2.addEventListener("click",function(){//添加事件
25 alert(123);
26 removeEventListener("click",function(){//解除监听事件
27 alert(123)
28 },false)
29 },false)
DOM事件流
事件流描述的是从页面中接收事件的顺序。 事件发生时会在元素节点之间按照特定的顺序传播,这个传播的过程叫做DOM事件流
DOM事件流分为三个阶段,分别为:
捕获阶段:事件从Document节点自上而下向目标节点传播的阶段;
目标阶段:真正的目标节点正在处理事件的阶段;
冒泡阶段:事件从目标节点自下而上向Document节点传播的阶段。
1.也就是你说当我们点击的时候,是从上到下进行监听的,首先接收点击事件,然后查看我们的document有没有绑定事件,没绑定的话继续向下寻找,经过了html,body,再继续向下查找直到找到我们的添加了点击事件的这个元素,这个阶段叫捕获阶段 2.然后找到了点击事件绑定的具体的元素节点(比如具体的某个div)这个阶段叫目标阶段 3.到达目标之后还没有结束,他会继续向上执行,也就是继续向上进行执行我们的点击事件。这个阶段叫冒泡阶段
注意: 1.js代码中只能执行捕获阶段或者冒泡阶段的其中一个阶段 2.onclick和attachEvent只能得到冒泡阶段
事件对象(重点)
event 对象代表事件的状态 也就是在触发的事件的函数里面我们会接收到一个event对象,这个对象有我们需要的一些参数,比如说我们需要知道此事件作用到谁身上了,就可以通过event的属性target来获取到(IE暂且不谈)
Node.onclick = function(event){
//我们把这里的形参叫做事件对象
// 括号内可以设置任意形参代替
}
在这里这个event是个形参,系统自动帮我们设置成为事件对象所以我们就不需要传递实参给它 在我们创建事件的时候系统就会自动帮我们创建这个事件对象,并且呢会依次传递给事件监听器(事件处理函数) IE9以下不识别,IE9以下需要从window.event中获取
事件对象属性方法: e.target //返回触发事件对象 (标准) e.srcElement //返回触发事件对象 (非标准,IE6-8使用) e.type //返回事件类型 比如click mouseover 不带on e.cancleBubble //阻止冒泡 (非标准 IE6-8使用) e.returnValue //阻止默认事件 例如a标签不跳转 (非标准IE6-8使用) e.preventDefault() //阻止默认事件(标准) e.stopPropagation() //阻止冒泡 (标准)
e.target 获取的是事件的触发元素 ,我们的实事件中还存在this这个关键字,两者的区别是,e.target 是点谁触发指向谁,this是谁调用就指向谁
兼容性问题: 在标准情况下浏览器传递的参数,只需要我们定义形参event就可以获取到 在ie9以下需要window.event中获取 兼容性处理就是 e = e || window.event
例:在选项卡中,利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上, ul 有注册事件,就会触发事件监听器,仅操作了一次DOM,提高了程序的性能。
阻止事件冒泡
e.stopPropagation() 正常浏览器可以使用
window.event.cancelBubble= false ie9以下可以使用
//兼容性处理
If(e){
e.stopPropagation()
}else{
window.event.cancelBubble= false
}
事件委托(代理、委托)
不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。只操作了一次 DOM ,提高了程序的性能
例:在选项卡中,利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上, ul 有注册事件,就会触发事件监听器。只操作了一次DOM,提高了程序性能。
常用的鼠标事件
onmousemove \ onmouseenter \ onmouseleave \ ...
oncontextmenu 鼠标右键点击事件
document.oncontextmenu = function(e){ 禁用鼠标右键
return false
}
onselectstart 鼠标选中内容事件
document. onselectstart = function(e){ 禁止选中内容
return false
}
//使用return方法有弊端,return后面的代码不会再被执行
鼠标的事件对象: e.clirntX //返回鼠标相对于浏览器窗口可视区的X坐标 e.clientY //返回鼠标相对于浏览器窗口可视区的Y坐标 e.pageX //返回鼠标相对于文档页的X坐标,IE9+支持(常用) e.pageY // __ e.screenX //返回鼠标相对于电脑屏幕的X坐标 e.screenY // __
常用的键盘事件
键盘事件的对象keycode
onkeyup 按键松开是触发
onkeydown 按键按下时触发
onkeypress 按键被按下并松开是触发
但是这里必须绑定给document文档对象
键盘事件的对象:keycode
document.onkeydown = function(e){//绑定键盘事件
console.log(e.keyCode)//每点击一个键,找到这个键的keyCode
if(e.keyCode == 13){//如果点击enter键,打印1
console.log(1)
}
}
JS的入口函数
JS 封装方法
轮播图插件
Swiper中文网-轮播图幻灯片js插件,H5页面前端开发
//设置鼠标以上分页器切换
//此方法为模拟的,hover到分页器的小圆点后自动触发其本身的click事件
$(".swiper-pagination-bullet").hover(function() {
$(this).click(); //鼠标划上去之后,自动触发点击事件来模仿鼠标划上去的事件
},function() {
mySwiper.autoplay.start(); //鼠标移出之后,自动轮播开启
})
autoplay: true,//自动轮播
autoplay :{//设置轮播属性
delay :0,//自动切换时间间隔 单位ms
disableOnInteraction:false//用户操作swiper后是否禁止autoplay
},
``
//自定义分页器
https://blog.csdn.net/qq_16371909/article/details/78247084
获取随机颜色 #000000
function randomcolor() {
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E']//设置数组,在此选择元素插入arr_
var arr_ = [] //设置颜色数组
for (var i = 0; i < 6; i++) { //设置6位循环
var a = Math.floor(Math.random() * 16) //设置0-16的随机数
arr_.push(arr[a]) //将下标位0-16的arr元素插入arr_中
}
var color = '#' + arr_.join('') //将颜色数组字符串拼接,形成随机颜色
return (color) //返回随机颜色
}
返回一个 a1 到 a2 之间的随机数
function fn(a1, a2) {
var num = Math.floor(Math.random() * (a2 - a1 + 1) + a1)
return(num)
}
//若需要多个,则在其中添加for循环即可
数组去重
var n = [6,3,5,9,0,5,7,6,1,4,2,3,6,7,8,5,4,3,9,0]
for(var i = 0 ;i< n.length; i++){
for(var j = i+1 ; j
数组普通排序
var arr = [5, 7, 9, 6, 3, 4, 2, 1, 8]
function ptpx(arr){
//普通排序
for (var i = 0; i < arr.length - 1; i++) {//j为i+1,省去一次循环步骤
for (var j = i + 1; j < arr.length; j++) {//在内循环中,i始终没变,相当于前面的数与后面每一个比较
if (arr[i] > arr[j]) {//当前下标为i的值与当前下标为j的进行比较,如果大于就准换位置
sun = arr[i]//第三方变量存储值并更换值
arr[i] = arr[j]
arr[j] = sun
}
}
}
return(arr)
}
数组冒泡排序
var n = [1, 2, 3, 4, 5, 6, 7, 8, 9, 5, 3, 1, 5, 6, 7, 3, 3, 3]
function mppx(n){
for(var i = 0 ; i< n.length-1;i++){//-1是因为大的数已经排在后面了,最前面的数已经是最小的了,不用再排一遍
for(var j = 0 ;j < n.length-i-1;j++ ){// -i是因为冒泡排序排在后面,后面的顺序已经排完,不用再参与排序;-1是因为if中有+1,在此补上
if(n[j] > n[j+1]){//比较相邻两数大小,如果后值较大,交换相邻两数位置
var k = ''
k = n[j+1]
n[j+1] = n[j]
n[j] = k
}
}
//数组排序
}
return(n)
}
截留锁
var look = true //在单击事件外
onclick//单击事件
if(!look){ return} //截留锁
look = false //单击后look为 false 在500ms内再次单击后将执行return 不执行后面的代码
setTimeout(function(){ //设置500ms的延时器,点击后过500ms才可以再次点击,500ms内将执行return,不执行后面的代码
look = true
},500)
各类框架插件
bootstrap (响应式) animate Element vantui Amaze ui
移动端JS
移动端浏览器兼容性较好,不需要考虑以前 JS 的兼容性问题,可以放心的使用原生 JS 书写效果,但是移动 端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android 和 IOS 都有。 touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是多跟手指。触屏事件可响应用户手指(或触控 笔)对屏幕或者触控板操作。 触摸事件 touchstart:手指触摸到屏幕会触发 touchmove:当手指在屏幕上移动时,会触发 touchend:当手指离开屏幕时,会触发
触摸事件对象(TouchEvent) TouchEvent 是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多 个触点,使开发者可以检测触点的移动,触点的增加和减少,等等 e.touches 正在触摸屏幕的所有手指的列表 e.targetTouches 正在触摸当前dom元素的手指列表 e.changedTouches 原来有现在没有或者原来没有现在有的手指列表当我们手指离开屏幕时,就没有了 touches和targetTouches列表但是会有changedTouches因为我们一半都是触摸元素,所以最经常使用的时targetTouches
移动端常见的开发插件: iScroll(GitHub - cubiq/iscroll: Smooth scrolling for the web) Swiper(Swiper中文网-轮播图幻灯片js插件,H5页面前端开发) SuperSlider(SuperSlide | TouchSlide 官方网站 大话主席) 移动端视频插件zy.media.js (H5提供了video标签,但是浏览器支持情况不同)其他视频插件还有腾讯云、保利威视 等(按流量计费)
移动端常用开发框架
前端常用的框架有 Bootstrap 前端三大框架 Angular、react、vue 他们非一个级别。Vue是框架,bootstrap是基于jQuery的组建库 只是统称为框架
MUI 原生UI前端框架 MUI 是一个专门用于做手机 APP 的前端框架。MUI-最接近原生APP体验的高性能前端框架
//bootstrap制作五列时的方法:12栅格底层原理是利用媒体查询
//在css中加入此媒体查询
//在使用时使用.col-zdlg-2-5 类名控制即可
click 延时解决方案
移动端 click 事件会有 300ms 的延时,原因是移动端屏幕默认双击会缩放(double tap to zoom) 页面 1.禁用缩放。 浏览器禁用默认的双击缩放行为并且去掉 300ms 的点击延迟
\2. 使用插件。 fastclick 插件解决 300ms 延迟。
document.addEventListener('DOMContentLoaded',function () {
// 等页面文档加载完成 不需要等所有的资源 //
FastClick.attach(document.body);
});
本地缓存
本地存储特性 : 1、数据存储在用户浏览器中 2、设置、读取方便、甚至页面刷新不丢失数据 3、容量较大,sessionStorage约5M 、localStorage约20M 4、只能存储字符串,可以将对象JSON.stringify() 编码后存储
window.sessionStorage 1.生命周期为关闭浏览器窗口 2.在同一个页面下可以共享数据 3.以键值对的形式进行存储 sessionStorage.setItem( ' key ' , value) 存数据 // 键值均为字符串 sessionStorage.getItem( ' key ' ) 取数据 sessionStorage.removeItem( ' key ' ) 删除单独的 sessionStorage.clear ( ) 删除所有的
window.localStorage 1.生命周期为永久生效,除非手动删除,否则关闭页面也会存在 2.可以多页面共享 (同一浏览器可以共享) 3.以键值对的形式存储数据 localStorage.setItem( ' key ' , value)存数据 localStorage.getItem( ' key ' )取数据 localStorage.removeItem( ' key ' )删除单独的 localStorage.clear ( ) 删除所有的
JSON.stringify( data ) //将对象编码为字符串,方可存入缓存
JSON.parse( )//从缓存中获取字符串对象,用此方法转换为正常对象使用
// parseInt() 函数解析字符串并返回整数。JQ方法
sessionStorage.setItem( ' key ' , value) 存数据//key为缓存中的名字,注意要用字符串
将对象转换为字符串:
var data = { //设置一个对象
name:11,
passowrd:123
}
var a = JSON.stringify(data) //将对象转换为字符串
console.log(a) // 转换为字符串后可以储存到本地缓存中
var b = JSON.parse(a) // 将字符串转回对象
console.log(b) // 从本地缓存中读取后,使用此方法变回对象
cookie 和 session 的区别
1.存储位置不同 cookie的数据信息存放在客户浏览器上 session的数据信息放在服务器上 2.存储容量不同 单个cookie保存的数据<= 4kb,一个站点最多保存20个Cookie 对于session来说并没有上限,但是对于服务器的性能考虑,session内不要存放过多的东西,并且设置session的删除机制 3.存储方式的不同 cookie中只能保管ASCII字符串,并需要通过编码方式存储为Unicode字符或者二进制数据 session中能够存储任何类型的数据 4.隐私策略不同 cookie对客户端是可见的,所以他是不安全的 session存储在服务器上,客户端是透明的,不存在敏感信息泄露的风险 5.有效期上不同 开发可以通过设置cookie的属性,达到使cookie长期有效的效果 session依赖于名为JSESSIONID的cookie,而cookie JSESSIONID的过期时间默认为-1,只需关闭窗口该session就会失效,因而session不能达到长期有效的效果 6.服务器压力不同 cookie保管在客户端,不占用服务器资源。对于并发用户十分多的网站,cookie是很好的选择 session是保管在服务器端的,每个用户都会产生一个session。假如并发访问的用户十分多,会产生十分多的session,耗费大量的内存 7.浏览器支持不同
假如客户端浏览器不支持cookie cookie是需要客户端浏览器支持的,假如客户端禁用了cookie,或者不支持cookie,则会话跟踪会失效。关于WAP上的应用,常规的cookie就派不上用场了 运用session需要使用URL地址重写的方式。一切用到session程序的URL都要进行URL地址重写,否则session会话跟踪还会失效
假如客户端支持cookie cookie既能够设为本浏览器窗口以及子窗口内有效,也能够设为一切窗口内有效 session只能在本窗口以及子窗口内有效
8.跨域支持不同 cookie支持跨域名访问 session不支持跨域名访问
JSON.parse()//将从缓存中获取的字符串对象转为正常对象
JSON.stringify()//将对象转换为字符串
页面间传参方式
第一种:利用缓存传参(如上) 第二种:利用a标签跳转传参
点击跳转到页面2 (页面1的a)
var str = location.search;(页面2的接收)
console.log(str) (接收?后的所有内容)//因为传值有中文,所以中文部分为乱码
JQuery
JQuery对象的本质:利用$对DOM对象包装后产生的对象
两个对象的相互转化: jQuery对象转换为DOM对象 1 $( ‘ span ’ ) [0]下标的方式 2 $( ‘ span ’ ) get ( index ) 索引的方式
$(function(){
$('.cont').click(function(){
console.log(this)//this指向DOM对象而不是JQuery对象
})
console.log($('#cont')[0])//JQuery对象转换为DOM对象
})
JQuery 入口函数
入口函数第一种 $(function(){ // ...此处是页面DOM加载完成的入口 })
入口函数第二种 $( document).ready(function(){ // ...此处是页面DOM加载完成的入口 })
这里的“$”可以换成jQuery • 等待DOM结构渲染完毕即可执行内部代码,不用等待所有外部资源加载完成,jQuery帮我们完成了封装 • 相当于DOMContentLoaded • 不同于原声的load事件是等页面文档,外部的js文件,css文件,图片加载完毕才执行内部代码 更推荐使用第一种方式
JQuery入口函数 与 JS入口函数的区别 1.JavaScript的入口函数比jQuery的入口函数早一些
2.jQuery的入口函数不会覆盖原有的入口函数,而会进行添加 javascript的入口函数执行的比jQuery的晚,且会进行覆盖 3.jQuery执行较早的好处 例如淘宝,京东这类大网站,图片等资源较多,若要等待全部加载就会导致代码执行很缓慢,因此文档树加载完成再执行代码执行会比较快些
JQ选择器
id选择器 $(‘#id’) 获取指定id元素 //此处全部与css选择器相同 class选择器 $(‘.calss’) 匹配指定类名的所有元素 标签选择器 $(‘div’) 获取标签名为div的同一类元素 全选选择器 $(‘*’) 匹配所有元素 并集选择器 $(‘div,li,span’)选取多个元素 交集选择器 $(‘li.current’) 交集元素 子代选择器$(‘ul>li’)子集选择器 后代选择器 $(‘ul li’) 后代选择器
寻找父元素 parent() // 返回被选元素的直接 父元素 parents() // 返回被选元素的所有祖先 元素,它一路向上直到文档的根元素() parentsUntil() // 返回介于两元素之间的所有祖先元素
$(document).ready(function(){
$("span").parentsUntil("div");//返回介于 与 元素之间的所有祖先元素
});
寻找子元素 children() // 返回被选元素的所有直接 子元素 find() // 返回被选元素的后代元素,一路向下直到最后一个后代
$("div").children("p");//返回所有 元素,并且它们是
的直接子元素
$("div").find("span");//返回属于
后代的所有
元素
$("div").find("*");//返回 的所有后代
寻找同胞 siblings ( ) // 返回被选元素的所有同胞元素(可选参数来过滤同胞,不包含自己) next ( ) // 返回下一个同胞元素(该方法只返回一个参数) nextAll ( ) // 返回被选元素的所有跟随的同胞元素 nextUntil ( ) // 返回介于两个给定参数之间的所有跟随的同胞元素 prev ( ) prevAll ( ) prevUntil ( ) // 以上三个方法的工作方式与上面的方法类似,只不过方向相反而已:它们返回的是前面的同胞元素
过滤 first ( ) // 返回被选元素的首个元素 last ( ) // 返回被选元素的最后一个元素 eq ( ) // 返回被选元素中带有指定索引号的元素 find( ) // 返回
filter ( ) // 方法允许您规定一个标准。不匹配这个标准的元素会被从集合中删除,匹配的元素会被返回 not ( ) // 返回不匹配标准的所有元素 odd ( ) // 返回奇数项元素 even ( ) // 返回偶数元素
$("div p").first().css("background-color","yellow");//返回首个 div 标签中 p 标签
$("p").eq(1).css("background-color","yellow");//返回p标签的第二个(index == 1)
$("p").filter(".url").css("background-color","yellow");//返回 p 标签中类名为 url 的所有元素
$("p").not(".url").css("background-color","yellow");//返回不带有类名 "url" 的所有 元素
JQ设置css样式
//方法一 设置单个css样式
$('div').css('属性名','属性值')
//方法二 设置多个css样式
$('div').css({ //css括号内为一个对象
'属性名':'属性值',
'属性名':'属性值',
})
参数只写属性名,则是返回属性值
$(this).css(''color'');
JQ操作类
添加类 $(“div”).addClass (''current''); 移除类 $(“div”).removeClass (''current''); 切换类 $(“div”).toggleClass (''current''); 检查类$(“div”).hasClass (''current'');//检查是否含有类名current 返回值为布尔
JQ操作类与JS操作className的区别 原生 JS 中 className 会覆盖元素原先里面的类名 jQuery 里面类操作只是对指定类进行操作,不影响原先的类名
JQ效果方法
显示隐藏 show() // 显示 hide ( ) // 隐藏 toggle ( ) // 切换
hide([speed],[easing],[fn]) // 参数可以全部省略 无动画直接显示
//speed 三种速度预设值 "slow" "normal" "fast" 也可以直接写毫秒 1000
//easing 用来指定切换效果 默认"swing" 可用 "linear"
// fn 回调函数 动画结束时执行
toggle([speed],[easing],[fn]) // 参数可以全部省略,无动画显示
滑动 slideDown ( ) // 下滑 slideUp ( ) // 上滑 slideToggle ( ) // 切换
slideToggle([speed],[easing],[fn]) // 参数可以全部省略 无动画直接显示
//speed 三种速度预设值 "slow" "normal" "fast" 也可以直接写毫秒 1000
//easing (Optional) 用来指定切换效果 默认"swing" 可用 "linear"
// fn 回调函数 动画结束时执行
淡入淡出 fadeIn ( ) // 淡入 fadeOut ( ) // 淡出 fadeToggle ( ) // 切换 fadeTo ( ) // 可设置透明度 ( 1000, .5 )
动画 animate ( )
animate(css,[speed],[easing],[fn])
// css: 想要更改的样式属性,以对象形式传递,必须写。 属性名可以不用带引号, 如果是复合属性则需要采取驼峰命名法 borderLeft。其余参数都可以省略
{height:’500px’,fontSize:’30px’}//css写法(px可以省略)
// speed:三种预定速度之一的字符串(“slow”,“normal”, or “fast”)或表示动画时长的毫秒数值(如:1000)
// easing:(Optional) 用来指定切换效果,默认是“swing”,可用参数“linear”
// fn 回调函数
JQ 遍历
each() 方法规定为每个匹配元素规定运行的函数 $( selector ) .each ( function ( index , element ) ) function(index,element) : index 为下标 e 为事件对象(也可以用" this " 选择器)
返回 false 可用于及早停止循环
stop()
stop() 方法用于在动画或效果完成前对它们进行停止 .stop() "停止" 会停止当前活动的动画,但允许已排队的动画向前执行 .stop(true) "停止所有" 停止当前活动的动画,并清空动画队列;因此元素上的所有动画都会停止 .stop(true,true) "停止但要完成" 会立即完成当前活动的动画,然后停下来
Callback 函数(回调函数)
在动画后可添加回调函数,在动画运行完成后可执行回调函数
$("button").click(function(){
$("p").hide(1000,function(){//回调函数,在动画结束后运行
alert("The paragraph is now hidden");
});
});
.hover ( ) 事件切换
hover( function(){} , function(){} ) 第一个函数为鼠标移上触发的函数(相当于mouseenter) 第二个函数为鼠标移出触发的函数(相当于mouseleave) 如果只写一个函数,则鼠标经过和离开都会触发
.hover ( ) 方法相当于鼠标移入与鼠标移出事件的合体
JQ属性操作(prop attr)
设置或获取元素固有属性 prop ( ) // 只能操作自带属性 设置或获取元素自定义属性 attr ( ) // 可以操作自带属性和自定义属性 移除属性 removeProp ( )
$(selector).attr({attribute:value, attribute:value ...})//设置多个属性注意引号
$(selector).attr(attribute)//返回该属性的属性值
.removeProp("color");//移除color属性
prop() 方法设置或返回被选元素的属性和值。 当该方法用于返回 属性值时,则返回第一个匹配元素的值。 当该方法用于设置 属性值时,则为匹配元素集合设置一个或多个属性/值对。 注意: prop() 方法应该用于检索属性值,例如 DOM 属性(如 selectedIndex, tagName, nodeName, nodeType, ownerDocument, defaultChecked, 和 defaultSelected)。 提示: 如需检索 HTML 属性,请使用 attr() 方法代替。
//回调函数
$("#w3s").attr("href", function(i,origValue){
return origValue + "/jquery"; //设置回调函数,返回值为要修改的属性值
});
数据缓存 .data ( )
data() 方法可以在指定的元素上存取数据,并不会修改 DOM 元素结构。一旦页面刷新,之前存放的数据都将被移除用于设置获取自定义属性
.data ( ' name ' ) // 返回name 属性值 .data ( ' name ' , ' value ' ) // 给被选元素添加name 属性 值为value(附加数据) .data ( ) // 以对象的方式返回所有存储的属性与属性值
只能读取HTML5自定义属性 data-index,得到的是数字型
设置内容
针对元素的内容的值操作 普通元素内容 .html() (相当于原生.innderHtml ) .html ( ) // 获取元素的内容 .html ( "内容" ) // 设置元素的内容 普通文本元素内容 .text() (相当于原生 .innerText ) .text ( ) // 获取元素的文本内容 .text ( "文本内容" ) // 设置元素的文本内容
针对表单值得操作 表单的值 val ( ) (相当于原生.value) .val ( ) // 获取表单的值 .val ( "内容" ) // 设置表单的值
//text的回调函数
$("#test1").text(function (i, origText) {//i为index,origText为原来的文本
return "Old text: " + origText + " New text: Hello world! (index: " + i + ")";//return返回的内容为要更改的内容 .text("内容")
});
.change ( ) 事件
当元素的值发生改变时,会发生change事件 该事件仅适用于表单元素 change() 函数触发 change 事件,或规定当发生 change 事件时运行的函数
//change()
$(".field").change(function(){
$(this).css("background-color","#FFFFCC");
});
each()遍历
.each ( ) 方法遍历匹配的每一个元素,主要是DOM处理,each每一个 里面的回调函数有两个参数,index为每个元素的索引,demEle是DOM元素对象,不是JQ对象 ,所以想要使用JQ方法,需要转换为JQ对象
$("div").each(function (index, domEle) { xxx; })
// domEle当前DOM元素,可以使用this选择器
.each(object,function (index, element) { xxx; })
// object 为遍历的对象
return false 可以提早种终止循环
创建插入删除对象
创建元素 语法: $( "
" ) 动态创建了一个div
插入对象 内部添加 (父子关系添加) .append ( "内容" ) // 将内容放入匹配元素内部的最后面(类似原生appendChind) .preprnd ( "内容" ) // 将内容放入匹配元素内部的最前面
外部添加 (兄弟关系添加) .after ( "内容" ) // 将内容放在匹配元素的后面 .before ( "内容" ) // 吧内容放在陪陪元素的前面
删除元素 .remove ( ) // 删除自己 .empty ( ) // 删除匹配元素集合的所有子节点 .html ( " " ) // 清空匹配的元素内容 // .empty() 和 .html("") 作用等价,都可以删除元素里面的内容,只不过html还可以设置内容
$('body').append("
" )//动态创建div并插入
$('.dt').html('123')//给div插入内容
$('.dt').text("
删除
${e.name}
型号:172471C102
颜色:白色
尺码:${e.size}
`
$('.gouwuche_main_sp').append(str)//再将动态字符串逐个插入要插入的盒子中
})
// parseInt() 函数解析字符串并返回整数。
JQ尺寸
width ( ) / height ( ) // 获取元素的宽高 (只有 width 和 height ) innerWidth ( ) / innerHeight ( ) // 获取宽高(包含padding) outerWidth ( ) / outerHeight ( ) // 获取宽高(包含padding、border) outerWidth ( true ) / outerHeight ( true ) // 获取宽高(含padding、border、margin) 以上参数为空,获取相应值,返回数字型 如果参数为数字,则为修改相应值 参数可不写单位
JQ位置
offset ( ) position ( ) scrollTop ( ) / scrollLeft ( )
offset( ) // 设置或获取 元素偏移 offset( ) 方法设置或返回元素相对于文档的偏移坐标,跟父级没有关系 该方法有两个属性 offset().top 获取距离文档顶部的距离,offset().left 同理 设置元素偏移:offset ( { top : 10 , left : 30 } )
position ( ) 获取元素偏移 position ( ) 用于返回被选元素相对于带有定位的父级偏移坐标,如果父级都没有定位则以文档为准 该方法有两个属性 top left 。position().top 用于获取举例定位父级顶部的距离,position().left 同理 该方法只能获取
scrollTop ( ) / scrollLeft ( ) 设置或获取 元素被卷去的部分 scrollTop() 设置或返回被选元素被卷去的头部 不跟参数是获取,参数为不带单位的数字为设置
on ( ) 绑定事件(事件委托)
on()方法在匹配元素(单个或多个)上绑定一个或多个事件的处理函数 element.on ( events , [ selector ] ,fn ) events:一个或多个用空格分隔的事件类型(例:click keydown) selector:元素的子元素选择器 fn:回调函数,即绑定在元素身上的侦听函数
如果有的事件只想触发一次, 可以使用 one( ) 来绑定事件
//on方法优势1:可以绑定多个事件,多个事件处理程序
$(“div”).on({
mouseover: function(){},
mouseout: function(){},
click: function(){}
});
//如果事件处理程序相同
$(“div”).on(“mouseover mouseout”, function() {
$(this).toggleClass(“current”);
})
//on()方法优势2:事件委托
$('ul').on('click', 'li', function() {
alert('hello world!');
});
//传入子集为事件委托
//不传入事件对象
在此前在此之前有bind(), live() delegate()等方法来处理事件绑定或者事件委派,最新版本的请用on()
//on()方法优势3:给动态创建的元素绑定事件
$("div").append($("我是动态创建的p
"));
$("div").on("click","p", function(){
alert("俺可以给动态生成的元素绑定事件")
});
off( ) 解绑事件 off() 方法可以移除通过 on() 方法添加的事件处理程序 $("p").off() // 解绑p元素所有事件处理程序 $("p").off( "click") // 解绑p元素上面的点击事件 后面的 foo 是侦听函数名$("ul").off("click", "li") // 解绑事件委托
自动触发事件trigger ( )
$("p").on("click", function () {//绑定p的click事件
console.log('Hi');
});
//第一种简写形式的自动触发:
$("p").click() //$("p")为一个对象,.click为对象内的属性,属性值为console.log('Hi'); 后加() 触发click
//第二种利用trigger()方法触发
$("p").trigger("click")
//第三种自动触发方式:
$("p").triggerHandler("click") // 第三种自动触发模式
//triggerHandler模式不会触发元素的默认行为,这是和前面两种的区别
JQ事件对象
$( ) .on(events , [ selector ] , function ( event ) { } )
//阻止默认行为:
$().preventDefault() // 或者
return false
//阻止冒泡:
$().stopPropagation()
JQ拷贝对象
$.extend ( [ deep ] , target , object1 , [ objextN ] ) deep: true为深拷贝,false为浅拷贝 target:要拷贝的目标对象 object1:待拷贝到第一个对象的对象
浅拷贝目标对象引用的被拷贝的对象地址,修改的目标会影响被拷贝对象 深拷贝,完全克隆,修改目标对象不会影响被拷贝对象
多库共存(修改JQ符号)
jQuery使用$作为标示符,随着jQuery的流行,其他 js 库也会用这$作为标识符, 这样一起使用会引起冲突 . jQuery 变量规定新的名称:$.noConflict() var xx = $.noConflict(); 将此段代码粘贴在引入的JQ中 来改变JQ的符号
JQ插件
jQuery 插件库 jQuery插件库-收集最全最新最好的jQuery插件
jQuery 之家 jQuery之家-自由分享jQuery、html5、css3的插件库
重点:瀑布流插件 图片懒加载插件
JQ 效果
//手风琴效果
//JQ全选效果
正则验证
修饰符 i ignore - 不区分大小写 g global - 全局匹配 m multi line - 多行匹配 使边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾
/a/g //全局匹配 a
/a/gi //全局匹配 a 不区分大小写
元字符
\ 将下一个字符标记为一个特殊字符 例如 \n 为换行
^ 输入匹配字符的起始位置 如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置
$ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置
+' 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"
{n} 匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o
{n,} 至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'
{n,m} 最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格
? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。
x|y 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。
[xyz] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'
[ ^xyz] 负值字符集合。匹配未包含的任意字符。例如, 'abc' 可以匹配 "plain" 中的'p'、'l'、'i'、'n'
[a-z] 字符范围。匹配指定范围内的任意字符
[ ^a-z] 同理
\d 匹配一个数字字符
\D 匹配一个非数字字符
\n 匹配一个换行符
\s 匹配任何空白字符,包括空格、制表符、换页符等等
\S 匹配任何非空白字符
\w 匹配数字、字母、下划线
\W 非数字、字母、下划线
匹配规则
^ 包含一个特殊的字符 ^ ,表示该模式只匹配那些以 once 开头的字符串。例如该模式与字符串 "once upon a time" 匹配,与 "There once was a man from NewYork" 不匹配。正如如 ^ 符号表示开头一样,$ 符号用来匹配那些以给定模式结尾的字符串
$ 只匹配结尾为该条件的
^abc$ 只匹配abc字符串
[a-z] // 匹配所有的小写字母
[A-Z] // 匹配所有的大写字母
[a-zA-Z] // 匹配所有的字母
[0-9] // 匹配所有的数字
[0-9\.\-] // 匹配所有的数字,句号和减号
[ \f\r\t\n] // 匹配所有的白字符
[^a-z] //除了小写字母以外的所有字符
[^\\\/\^] //除了(\)(/)(^)之外的所有字符
[^\"\'] //除了双引号(")和单引号(')之外的所有字符
/ [ 0-9 ] + / // 是否有0-9的数字(+代表可以有很多个数字) / a / // 是否有 a
var reg = /a/;
var str = "wrhgatd";
console.log(reg.test(str))//判断str字符串中有没有a
var objRegExp= /^\d+\.\d+$/;// ^ 为起始符 $ 为结束符 \d 为数字 + 代表可以有好几个数字 \.只有一个
var num = 123.23 ;
console.log(objRegExp.test(num))//判断数字间是否带有小数
var reg = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/;//邮箱
name_tj = /^[1][3,4,5,7,8][0-9]{9}$///手机号
一、校验数字的表达式
数字:^[0-9]*$
n位的数字:^\d{n}$
至少n位的数字:^\d{n,}$
m-n位的数字:^\d{m,n}$
零和非零开头的数字:^(0|[1-9][0-9]*)$
非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
非零的负整数:^\-[1-9][]0-9″*$ 或 ^-[1-9]\d*$
非负整数:^\d+$ 或 ^[1-9]\d*|0$
非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
二、校验字符的表达式
汉字:^[\u4e00-\u9fa5]{0,}$
英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
长度为3-20的所有字符:^.{3,20}$
由26个英文字母组成的字符串:^[A-Za-z]+$
由26个大写英文字母组成的字符串:^[A-Z]+$
由26个小写英文字母组成的字符串:^[a-z]+$
由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
可以输入含有^%&',;=?$\”等字符:[^%&',;=?$\x22]+
禁止输入含有~的字符:[^~\x22]+
三、特殊需求表达式
Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
电话号码(“XXX-XXXXXXX”、”XXXX-XXXXXXXX”、”XXX-XXXXXXX”、”XXX-XXXXXXXX”、”XXXXXXX”和”XXXXXXXX):^($$\d{3,4}-)|\d{3.4}-)?\d{7,8}$
国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
身份证号(15位、18位数字):^\d{15}|\d{18}$
短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
日期格式:^\d{4}-\d{1,2}-\d{1,2}
一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
钱的输入格式:
有四种钱的表示形式我们可以接受:”10000.00″ 和 “10,000.00″, 和没有 “分” 的 “10000″ 和 “10,000″:^[1-9][0-9]*$
这表示任意一个不以0开头的数字,但是,这也意味着一个字符”0″不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
必须说明的是,小数点后面至少应该有1位数,所以”10.”是不通过的,但是 “10″ 和 “10.2″ 是通过的:^[0-9]+(.[0-9]{2})?$
这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
这样就允许用户只写一位小数。下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
备注:这就是最终结果了,别忘了”+”可以用”*”替代。如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
中文字符的正则表达式:[\u4e00-\u9fa5]
双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
空白行的正则表达式:\n\s*\r (可以用来删除空白行)
HTML标记的正则表达式:<(\S*?)[^>]*>.*?\1>|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)
IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))
四、字母,数字,下划线或者数字的正则表达式
1.由数字、26个英文字母或者下划线组成的字符串:
^[0-9a-zA-Z_]{1,}$
2.非负整数(正整数 + 0 ):
^/d+$
3. 正整数:
^[0-9]*[1-9][0-9]*$
4.非正整数(负整数 + 0):
^((-/d+)|(0+))$
5. 负整数 :
^-[0-9]*[1-9][0-9]*$
6.整数:
^-?/d+$
7.非负浮点数(正浮点数 + 0):
^/d+(/./d+)?$
8.正浮点数 :
^(([0-9]+/.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*))$
9. 非正浮点数(负浮点数 + 0):
^((-/d+(/./d+)?)|(0+(/.0+)?))$
10.负浮点数 :
^(-(([0-9]+/.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*)))$
11. 浮点数 :
^(-?/d+)(/./d+)?$
12.由26个英文字母组成的字符串 :
^[A-Za-z]+$
13. 由26个英文字母的大写组成的字符串 :
^[A-Z]+$
14.由26个英文字母的小写组成的字符串 :
^[a-z]+$
15. 由数字和26个英文字母组成的字符串 :
^[A-Za-z0-9]+$
16.由数字、26个英文字母或者下划线组成的字符串 :
^/w+$
17.email地址 :
^[/w-]+(/.[/w-]+)*@[/w-]+(/.[/w-]+)+$
18.url:
^[a-zA-z]+://(/w+(-/w+)*)(/.(/w+(-/w+)*))*(/?/S*)?$
19. 年-月-日:
/^(d{2}|d{4})-((0([1-9]{1}))|(1[1|2]))-(([0-2]([1-9]{1}))|(3[0|1]))$/
20.月/日/年:
/^((0([1-9]{1}))|(1[1|2]))/(([0-2]([1-9]{1}))|(3[0|1]))/(d{2}|d{4})$/
21.Emil:
^([w-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([w-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)$
22. 电话号码:
(d+-)?(d{4}-?d{7}|d{3}-?d{8}|^d{7,8})(-d+)?
23.IP地址:
^(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5])$
24. 匹配中文字符的正则表达式:
[/u4e00-/u9fa5]
25.匹配双字节字符(包括汉字在内):
[^/x00-/xff]
26. 匹配空行的正则表达式:
/n[/s| ]*/r
27.匹配HTML标记的正则表达式:
/<(.*)>.*//1>|<(.*) //>/
28.匹配首尾空格的正则表达式:
(^/s*)|(/s*$)
29.匹配Email地址的正则表达式:
/w+([-+.]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)*
30. 匹配网址URL的正则表达式:
^[a-zA-z]+://(//w+(-//w+)*)(//.(//w+(-//w+)*))*(//?//S*)?$
31. 匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):
^[a-zA-Z][a-zA-Z0-9_]{4,15}$
32. 匹配国内电话号码:
(/d{3}-|/d{4}-)?(/d{8}|/d{7})?
33.匹配腾讯QQ号:
^[1-9]*[1-9][0-9]*$
34. 只能输入数字:
^[0-9]*$
35.只能输入n位的数字:
^/d{n}$
36.只能输入至少n位的数字:
^/d{n,}$
37.只能输入m~n位的数字:
^/d{m,n}$
38.只能输入零和非零开头的数字:
^(0|[1-9][0-9]*)$
39.只能输入有两位小数的正实数:
^[0-9]+(.[0-9]{2})?$
40. 只能输入有1~3位小数的正实数:
^[0-9]+(.[0-9]{1,3})?$
41.只能输入非零的正整数:
^/+?[1-9][0-9]*$
42. 只能输入非零的负整数:
^/-[1-9][0-9]*$
43.只能输入长度为3的字符:
^.{3}$
44. 只能输入由26个英文字母组成的字符串:
^[A-Za-z]+$
45.只能输入由26个大写英文字母组成的字符串:
^[A-Z]+$
46. 只能输入由26个小写英文字母组成的字符串:
^[a-z]+$
47.只能输入由数字和26个英文字母组成的字符串:
^[A-Za-z0-9]+$
48. 只能输入由数字和26个英文字母或者下划线组成的字符串:
^/w+$
49.验证用户密码(正确格式为: 以字母开头,长度在5~17 之间,只能包含字符、数字和下划线)
^[a-zA-Z]/w{5,17}$
50.验证是否包含有 ^%&',;=?$/"等字符:
[^%&',;=?$/x22]+
51.只能输入汉字:
^[\u4e00-\u9fa5]{0,}$
52、只含有汉字、数字、字母、下划线不能以下划线开头和结尾
^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$
53、只含有汉字、数字、字母、下划线,下划线位置不限
^[a-zA-Z0-9_\u4e00-\u9fa5]+$
54、2~4个汉字
@"^[\u4E00-\u9FA5]{2,4}$
AJAX
AJAX = Asynchronous JavaScript and XML(异步 的 JavaScript 和 XML)现为JS和JSON 优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容 以JS为底层,JQ封装了AJAX方法
在没有AJAX前使用表单传递数据,但是表单不能实现异步。会跳转
前端与服务器之间存在跨域问题,服务器之间不存在跨域问题
get/post 方法
JQuery 封装的AJAX
$.ajax() 方法
type:
1. ' get ' (查看)会向数据库发索取数据的请求,从而来获取信息。只是用来查询一下数据,不会修改、增加数据,不会影响资源的内容,即该请求不会产生副作用。无论进行多少次操作,结果都是一样的
2. ’ put ‘ (更新)向服务器端发送数据的,从而改变信息.用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同
3. ' post ' (创建)向服务器端发送数据的,但是该请求会改变数据的种类等资源,会创建新的内容。几乎目前所有的提交操作都是用POST请求的
4. ' delete ' (删除)删除某一个资源的
$.ajax({//AJAX方法,内为对象
type:'get',//AJAX类型,此处为获取(共有四种类型,常用两种)默认get
url:'1.json',//获取地址
data:{},//传递参数
dataType:"json",
async:true,//是否异步
success:function(res){//成功获取后执行函数
console.log(res);//res为获取到的数据对象,需要逐层找到需要使用的信息
},
error:function(res){//获取失败后执行函数
console.log(res);//打印res可以获得详细的错误详情
}
})
$.get ( ) 和 $.post ( ) 是简易写法,高层的实现,在调用他们的时候,会运行底层封装好的$.ajax
$.get ( ) 方法 - 从指定的资源请求数据 (基本用于取回数据,可能返回缓存数据) $.get() 方法通过 HTTP GET 请求从服务器上请求数据
$("button").click(function(){
$.get("demo_test.php",function(data,status){//get()的第一个参数为请求的地址 第二个是回调函数
alert("数据: " + data + "\n状态: " + status);//函数内的data存有被请求页面的内容 status 存有请求的状态
});
});
$.post( ) 方法 - 向指定的资源提交要处理的数据(也可用于获取数据,但post不会缓存数据,且常用于联通请求一起发送数据) $.post() 方法通过 HTTP POST 请求向服务器提交数据
$("button").click(function(){
$.post("/try/ajax/demo_test_post.php",//第一个参数为希望请求的地址
{//此对象为请求,连同请求一起发送数据
name:"菜鸟教程",
url:"http://www.runoob.com"
},
function(data,status){//data存有被请求页面的内容 status 存有请求的状态
alert("数据: \n" + data + "\n状态: " + status);
});
});
原生AJAX
get请求方式:
function ajax() {
//创建核心对象
xhr = null;
if(window.XMLHttpRequest){//新版本浏览器可以直接创建对象,判断此浏览器有没有此对象
xhr = new XMLHttpRequest();//创建对象
}else if(window.ActiveXObject){//IE5或IE6没有XMLHttpRequest对象
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
//编写回调函数
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){//readystate 判断XMLHttpRequest 状态 (4为请求完成且响应就绪) xhr.status:获取当前服务器的响应状态 200=>成功
console.log(xhr.responseText)//打印获取的数据
}
}
//设置open请求方式和请求路径
xhr.open("get","/Ajax/ajax?userId=10",true);//一个URL还传递了数据,true为异步
//send发送
xhr.send();
}
post请求方式
function ajax() {
//创建核心对象
xhr = null;
if (window.XMLHttpRequest) {//新版本浏览器可以直接创建对象,判断此浏览器有没有此对象
xhr = new XMLHttpRequest();//创建对象
} else if (window.ActiveXObject) {//IE5或IE6没有XMLHttpRequest对象
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
//编写回调函数
xhr.onreadystatechange = function(){
if (xhr.readyState == 4 && xhr.status == 200) {//readystate 判断XMLHttpRequest 状态 (4为请求完成且响应就绪) xhr.status:获取当前服务器的响应状态 200=>成功
console.log(xhr.responseText)//打印获取的数据
}
}
//open设置请求方式和请求路径
xhr.open("post","/Ajax/ajax2",true)//一个servlet true为异步
//设置请求头(POST)
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
//send发送
xhr.send("userId = 10");
}
readystate : 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化 0 :请求未初始化 1 :服务器已建立 2 :请求已接收 3 :请求处理中 4 :请求已完成,且响应已就绪
status : 200 : ' OK ' 404 : 未找到页面 405 : 请求方式不正确 500 : 服务器内部错误 403 : 禁止请求
封装好的原生ajax方法 :
function ajax(url){
//创建XMLHttpRequest对象,新版本浏览器直接创建,IE5 IE6创建ActiveXObject对象
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : ActiveXObject("microsoft.XMLHttp")
xhr.open("get",url,true);
xhr.send();//发送请求
xhr.onreadystatechange = () => {
if(xhr.readyState == 4){//返回存有 XMLHttpRequest 的状态
if(xhr.status == 200){//返回状态码
var data = xhr.responseText;
return data;
}
}
}
}
表单的提交方法(了解)
ES6语法(ECMAScript)
ES6 是 JavaScript 语言的下一代标准,使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
let 与 const 声明
let 用来声明变量,但是所声明的变量只在命令所在的代码块内有效,没有变量提升
//for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域
for (let i = 0; i < 3; i++) {//父作用域
let i = 'abc';//子作用域
console.log(i);
}
// abc(将会打印三遍)
// abc
// abc
var
命令会发生“变量提升”
现象,即变量可以在声明之前使用,值为undefined 为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明后
使用,否则报错
暂时性死区 只要块级作用域内存在let
命令,它所声明的变量就“绑定”(binding)
这个区域,不再受外部的影响
var tmp = 123;//全局声明变量
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;// let 声明的 tmp 绑定了这个区域,所以4行代码将会报出赋值错误
}
//存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)
不允许重复声明 块级作用域 ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域 ES5 只有全局作用域
和函数作用域
,没有块级作用域,这带来很多不合理的场景:
内层变量可能会覆盖外层变量
用来计数的循环变量泄露为全局变量
const声明常量
const
声明一个只读的常量
。一旦声明,常量的值就不能改变。 const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化
(赋值),不能留到以后赋值。
只在声明所在的块级作用域
内有效。 不提升,同样存在暂时性死区
本质 const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心
字符串的扩展
字符串模板
const box = document.querySelector(".box");
let id = 1;
let title = "腾讯新闻";
let str = "";
str = `
`;
box.innerHTML = str;
字符串的遍历接口
字符串可以被for...of
循环遍历
var str = 'foo';
for (let x of str) {
console.log(x)
}
// "f"
// "o"
// "o"
除了遍历字符串,这个遍历器最大的优点是可以识别大于0xFFFF
的码点,传统的for
循环无法识别这样的码点
repeat ( ) 重复方法
repeat
方法返回一个新字符串,表示将原字符串重复n
次
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
padStart(),padEnd() 补全字符串
ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()
用于头部补全,padEnd()
用于尾部补全 第一个参数为字符串的最大长度 第二个参数为补全字符串的字符 第二个参数为空时默认用空格补全字符串
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
//在开头补全
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
//在末尾补全
//如果原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串。
'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'
//padStart()的常见用途是为数值补全指定位数。下面代码生成 10 位的数值字符串。
'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"
'123456'.padStart(10, '0') // "0000123456"
//另一个用途是提示字符串格式。
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
trim()清除字符串空格
const s = ' abc ';
s.trim() // "abc" 清除所有空格
s.trimStart() // "abc " 清除前端空格
s.trimEnd() // " abc" 清除后端空格
Math 对象的扩展
Math.trunc
方法用于去除一个数的小数部分,返回整数部分
Math.trunc(4.1) // 4
Math.trunc('123.456') // 123
Math.trunc(false) // 0
//对于空值和无法截取整数的值,返回NaN
Math.trunc('foo'); // NaN
Math.sign
方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值
//参数为正数,返回+1;
Math.sign(-5) // -1
//参数为负数,返回-1;
//参数为 0,返回0;
//参数为-0,返回-0;
//其他值,返回NaN
函数的扩展
//1.带参数默认值的函数
//es5写法
// function add(a,b){
// a= a||2;
// b=b||6;
// return a+b;
// }
// es6
function add(a=1,b=6){
return a+b;
}
console.log(add(3))//9 a = 3 (赋值); b = 6 (默认)
console.log(add(3,3))
// 2.默认的表达式也可以是一个函数
function add(a,b=getVal(2)){//a = 10
return a+b;
}
function getVal(val){
return val+5;
}
console.log(add(10))//17
ES6 引入 rest 参数(形式为...变量名
),用于获取函数的多余参数,这样就不需要使用arguments
对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中
// 3.剩余参数(剩余运算符)(有三个点... 和紧跟着的参数指定 ...keys)
// 4.扩展运算符
const MaxNum = Math.max(50,20);
console.log(MaxNum);
// es5处理数组中的最大值 ,使用apply
const arr = [1,2,4,7,100,40];
// const maxNum = Math.max(arr);会报错哦
const maxNum = Math.max.apply(null,arr);
console.log(maxNum);
// es6扩展运算符
console.log(Math.max(...arr));
箭头函数
箭头函数没有this指向,在哪个作用域声明的箭头函数,箭头函数的this就指向谁。若外部没有作用域(函数作用域),this会一直指向window
箭头函数不是函数,是一个表达式。所以没有arguments,也没有作用域链
箭头函数没有构造器,因此不能使用new关键字实例化对象
// 5.es6中使用箭头函数
// let add = function(a,b){
// return a+b;
// }
// 两个参数
// let add = (a,b)=>{
// return a+b;
// }
// let add = (a,b)=>(a+b);
// let add = (a,b)=>a+b;
// console.log(add(2,3))
// 一个参数
// let add = val=>val
// console.log(add(5))//5
let add = val=>(val+5)
console.log(add(10))//15
// 无参数
// let fn = ()=>{
// return "haha";
// }
// let fn = ()=> "haha";
// let fn = ()=>"haha"+123;
// console.log(fn())
let getObj = (id)=>{
return {
id:id,
name:"张三"
}
}
// 简单写法,一定要加();
// let getObj = (id)=>({id:id,name:"张三"})
console.log(getObj(2))
箭头函数的this指向
箭头函数体内的this
对象,就是定义该函数时所在的作用域指向的对象 ,而不是调用时所在的作用域指向的对象。
var name = 'window';
var A = {
name: 'A',
sayHello: () => {
console.log(this.name)
}
}
A.sayHello();//输出的是window
//"定义该函数所在的作用域指向的对象”,作用域是指函数内部,这里的箭头函数,也就是sayHello,所在的作用域其实是最外层的js环境,因为没有其他函数包裹;然后最外层的js环境指向的对象是winodw对象,所以这里的this指向的是window对象
若要绑定A对象:
var name = 'window';
var A = {
name: 'A',
sayHello: function(){
var s = () => console.log(this.name)
return s//返回箭头函数s
}
}
var sayHello = A.sayHello();
sayHello();// 输出A
var B = {
name: 'B';
}
sayHello.call(B); //不管是谁调用,this指向都是A
sayHello.call(); //还是A
数组的扩展
扩展运算符
扩展运算符(spread)是三个点(...
)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列 该运算符主要用于函数调用 (传递参数) 只有函数调用时,扩展运算符才可以放在圆括号中,否则会报错 替代函数的 apply 方法
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [,
,
]
function add2(...args){
console.log(args);//['a', 'b', 'c']
console.log(arguments);//Arguments(3) ['a', 'b', 'c', callee: (...), Symbol(Symbol.iterator): ƒ]
}
add2("a","b","c");
let arr = [1,2,3,4,5,6,7,8,9]
let max = Math.max(...arr)//此处如果传入arr将会报错
console.log(max)//9
//参数接收的arguments为伪数组,而...keys 为真正的数组
扩展运算符可以用来合并数组 ( 两种方法都是浅拷贝 )
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];
// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
扩展运算符与解构赋值结合
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
const [first, ...rest] = [];
first // undefined
rest // []
const [first, ...rest] = ["foo"];
first // "foo"
rest // []
如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错
const [...butLast, last] = [1, 2, 3, 4, 5];
// 报错
const [first, ...middle, last] = [1, 2, 3, 4, 5];
// 报错
将字符串转为数组
[...'hello']
// [ "h", "e", "l", "l", "o" ]
数组的空位
数组的空位指,数组的某一个位置没有任何值。比如,Array
构造函数返回的数组都是空位
Array(3) // [, , ,]
ES5不识别空位 ES6将空位转为undefind 扩展运算符(...
)也会将空位转为undefined
copyWithin()
会连空位一起拷贝 for...of
循环也会遍历空位。
from()转化数组
Array.from
方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
// NodeList对象
let ps = document.querySelectorAll('p');//获取所有的p标签
Array.from(ps).filter(p => {//from转换为数组 filter将不符合要求的p元素从数组中去除
return p.textContent.length > 100;
});
// arguments对象
function foo() {
var args = Array.from(arguments);//将参数存储的伪数组转换为真正的数组
}
//将字符串转换为数组
Array.from('hello')//更建议使用{...str}的方法
// ['h', 'e', 'l', 'l', 'o']
copyWithin()数组内部覆盖
Array.copyWithin(target, start = 0, end = this.length)
// target(必需):从该位置开始替换数据。如果为负值,表示倒数。
// start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示从末尾开始计算。
// end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示从末尾开始计算。
find() 和 findIndex()
数组实例的find
方法,用于找出第一个 符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true
的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined
。
[1, 4, -5, 10].find((n) => n < 0)
// -5
find
方法的回调函数可以接受三个参数 ,依次为当前的值、当前的位置和原数组。
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10
数组实例的findIndex
方法的用法与find
方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1
fill()填充数组
fill
方法使用给定值,填充一个数组。数组中已有的元素,会被全部抹去。
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
fill
方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
注意,如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象。
includes() 数组包含
传入一个值时
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
[1, 2, NaN].includes(NaN) // true
该方法的第二个参数表示搜索的起始位置,默认为0
。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4
,但数组长度为3
),则会重置为从0
开始。
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true 从倒数第一位开始找
flat() 拉开多维数组
用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。
[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]
默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()
方法的参数写成一个整数,表示想要拉平的层数,默认为1。
[1, 2, [3, [4, 5]]].flat()
// [1, 2, 3, [4, 5]]
[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]
如果不管有多少层嵌套,都要转成一维数组,可以用Infinity
关键字作为参数。
[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]
如果原数组有空位,flat()
方法会跳过空位。
[1, 2, , 4, 5].flat()
// [1, 2, 4, 5]
遍历数组
entries() ,keys() 和 values() ——用于遍历数组。 它们都返回一个遍历器对象 可以用for...of
循环进行遍历,唯一的区别是keys()
是对键名的遍历、values()
是对键值的遍历,entries()
是对键值对的遍历。
entries()
Object.entries() 方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)
var obj = {
name:'lishuo',
age:22
}
console.log(Object.entries(obj))
// ['name', 'lishuo']
// ['age', 22]
//返回为数组
var obj = {
name: 'lishuo',
age: 22
}
for (const [key, value] of Object.entries(obj)) {
console.log(`${key}: ${value}`);
}
// name: lishuo
// age: 22
//返回为字符串
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
对象的扩展
属性的简介表示
在大括号里面,直接写入变量和函数,作为对象的属性和方法。
//属性简写
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于
const baz = {foo: foo};
//属性简写
function f(x, y) {
return {x, y};
}
// 等同于
function f(x, y) {
return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}
//方法简写
const o = {
method() {
return "Hello!";
}
};
// 等同于
const o = {
method: function() {
return "Hello!";
}
};
取值器
const student = {//const存储的是对象的指针,并不是对象本身,所以该对象内容可以被改变。使用const声明对象只能保证该指针不会被改变
num:22,
getnum(){
return this.num;
},
setnum(num){
this.num = num
return `num:${this.num}`
}
}
student.setnum(5);
console.log(student.getnum());
属性名表达式
旧方法定义对象属性:
// 方法一
obj.foo = true;
// 方法二
obj['a' + 'bc'] = 123;
//方法三
var obj = {
foo: true,
abc: 123
};
允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内。
let propKey = 'foo';
let obj = {
[propKey]: true,// foo:true
['a' + 'bc']: 123,// abc:123
['h' + 'ello']() { //hello:function(){}
return 'hi';
}
};
注意,属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object]
,这一点要特别小心。
const keyA = {a: 1};
const keyB = {b: 2};
const myObject = {
[keyA]: 'valueA',
[keyB]: 'valueB'
};
myObject // Object {[object Object]: "valueB"}
方法的name属性
const person = {
sayName() {
console.log('hello!');
},
};
person.sayName.name // "sayName"
对象的super指向
this
关键字总是指向函数所在的当前对象,ES6 又新增了另一个类似的关键字super
,指向当前对象的原型对象。
对象内的扩展运算符
对象的扩展运算符(...
)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
由于数组是特殊的对象,所以对象的扩展运算符也可以用于数组。
let foo = { ...['a', 'b', 'c'] };
foo
// {0: "a", 1: "b", 2: "c"}
解构赋值
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }
//解构赋值要求等号右边是一个对象,所以如果等号右边是undefined或null,就会报错,因为它们无法转为对象。
//解构赋值必须是最后一个参数,否则会报错。
//解构赋值为浅拷贝!
对象的遍历
ES2017 引入了跟Object.keys
配套的Object.values
和Object.entries
,作为遍历一个对象的补充手段,供for...of
循环使用。
对象的新增方法
is() 判断全等
它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
assign() 对象合并
将源对象(source)的所有可枚举属性,复制到目标对象(target)。
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
第一个参数是目标对象,后面的参数都是源对象。 注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。 如果该参数不是对象,则会先转成对象,然后返回。
解构赋值
解构赋值(数组)
剩余操作符:...
写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
let [x, , y] = [1, 2, 3];
x // 1
y // 3
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
//不完全解构
let [x, y] = [1, 2, 3];
x // 1
y // 2
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
解构赋值允许默认值
let [foo = true] = [];
foo // true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
//注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效
//上面代码中,如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined
例:
let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null
解构赋值(对象)
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值
let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"
let { baz } = { foo: 'aaa', bar: 'bbb' };
baz // undefined
//对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
//上面代码中,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。
//与数组一样,解构也可以用于嵌套结构的对象
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
//默认值
var {x = 3} = {};
x // 3
var {x, y = 5} = {x: 1};
x // 1
y // 5
var {x: y = 3} = {};
y // 3
var {x: y = 3} = {x: 5};
y // 5
解构赋值(注意)
// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error
上面代码的写法会报错,因为 JavaScript 引擎会将{x}
理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题
// 正确的写法
let x;
({x} = {x: 1});
由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3
// 2行中 0为匹配模式,first才是变量,值为1
解构赋值(字符串)
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。 类似数组的对象都有一个length
属性,因此还可以对这个属性解构赋值。
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
let {length : len} = 'hello';
len // 5
解构赋值(函数)
新的数据类型 Symbol
JavaScript标准中规定对象的key只能是 String
或 Symbol
类型,区别在于 String
类型的key可以重复而 Symbol
类型的key是唯一的。Symbol
的本质是表示一个唯一标识 。每次创建一个Symbol,它所代表的值都不可能重复
const sym = Symbol();
const sym = Symbol('cat');
//传入一个字符串参数(descriptor)用于描述该Symbol:
console.log(sym)//Symbol(cat)
最大的用途就是用来定义对象的私有属性
const name = Symbol("name");
const name2 = Symbol("name");
console.log(name === name2);//false
//其内存地址不相同
Symbol属性无法正常遍历 不易操作,因此不常用
获取Symbol属性可以使用特定的方法Object.getOwnPropertySymbols()
var Obj = {
}
var a = Symbol("a");
Obj[a] = '123'
var objectSymbols = Object.getOwnPropertySymbols(Obj);
console.log(objectSymbols.length)//1
console.log(objectSymbols)//[Symbol(a)]
获取Symbol属性也可以使用反射
const name = Symbol("name");
const age = Symbol("age");
let person = {
[name]:"张三",
[age]:"10",
sex:"男"
};
let kk = Reflect.ownKeys(person);//遍历键
console.log(kk);//Array(3)["sex" , Symbol(name) , Symbol(age)]
for(let i=0;i
Promise 对象
Promise
,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果
Promise 对象的特点:
1.对象的状态不受外界影响。 Promise 对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
2.一旦状态改变,就不会再变,任何时候都可以得到这个结果。 Promise 对象的状态改变,只有两种情况:进行中到已成功、进行中到已失败。只要这两种情况发生,状态就凝固了,不会再改变。
Promise 对象的缺点: 1.无法取消 Promise 一旦新建它就会立即执行,无法中途取消。 2.如果不设置回调函数,Promise
内部抛出的错误,不会反应到外部。 3.当处于pending
(进行中)状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
ES6 规定,Promise
对象是一个构造函数,用来生成Promise
实例。
//创建promise对象
var myFirstPromise = new Promise(function(resolve, reject){
//当异步代码执行成功时,我们才会调用resolve(...), 当异步代码失败时就会调用reject(...)
//在本例中,我们使用setTimeout(...)来模拟异步代码,实际编码时可能是XHR请求或是HTML5的一些API方法.
setTimeout(function(){
resolve("成功!"); //代码正常执行!
}, 250);
});
myFirstPromise.then(function(successMessage){
//successMessage的值是上面调用resolve(...)方法传入的值.
//successMessage参数不一定非要是字符串类型,这里只是举个例子
document.write("Yay! " + successMessage);
});
//创建promise对象
let p = new Promise((resolve,reject)=>{
setTimeout(() => {//模拟异步操作
reject('失败');
resolve('成功')
}, 2000);
})
p.then((res)=>{
console.log(res);//成功
})
对于已经实例化过的 promise 对象可以调用 promise.then() 方法,传递 resolve 和 reject 方法作为回调。
then() 方法
then() 方法返回一个 Promise
。它最多需要有两个参数:Promise 的成功和失败情况的回调函数。
then方法可以链式操作
const promise1 = new Promise((resolve, reject) => {
resolve('Success!');//成功时返回
reject('error!');//失败时返回
});
promise1.then((value) => {//接收返回值
console.log(value);
// expected output: "Success!"
});
语法:promise.then(onCompleted, onRejected); 参数:
resolve()方法
resolve()方法可以把任何对象转化成 Promise 对象
let p = Promise.resolve("啊哈哈");
let p = new Promise(resolve=>resolve("foo"));
p.then((res)=>{
console.log(res);
})
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
如果参数是 Promise 实例 ,那么Promise.resolve
将不做任何修改、原封不动地返回这个实例。
参数是一个thenable
对象 ,(thenable
对象指的是具有then
方法的对象),会将这个对象转为 Promise 对象,然后就立即执行thenable
对象的then
方法。
参数不是具有then
方法的对象,或根本就不是对象 ,方法返回一个新的 Promise 对象,状态为resolved
。
不带有任何参数 ,方法允许调用时不带参数,直接返回一个resolved
状态的 Promise 对象。
reject() 方法
返回一个新的 Promise 实例,该实例的状态为rejected
。
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s) {
console.log(s)
});
// 出错了
注意,Promise.reject()
方法的参数,会原封不动地作为reject
的理由,变成后续方法的参数。这一点与Promise.resolve
方法不一致。
all() 方法
用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
//p1 p2 p3 都是 promise 实例
//如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
p
的状态由p1
、p2
、p3
决定,分成两种情况: (1)只有p1
、p2
、p3
的状态都变成fulfilled
(成功),p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数。
(2)只要p1
、p2
、p3
之中有一个被rejected
(失败),p
的状态就变成rejected
,此时第一个被reject
的实例的返回值,会传递给p
的回调函数。
注意,如果作为参数的 Promise 实例,自己定义了catch
方法,那么它一旦被rejected
,并不会触发Promise.all()
的catch
方法。(执行自己的catch)
catch() 方法
Promise.prototype.catch()
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。
getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});
上面代码中,getJSON()
方法返回一个 Promise 对象,如果该对象状态变为resolved
,则会调用then()
方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected
,就会调用catch()
方法指定的回调函数,处理这个错误。另外,then()
方法指定的回调函数,如果运行中抛出错误,也会被catch()
方法捕获。
race() 方法
Promise.race()
方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
上面代码中,只要p1
、p2
、p3
之中有一个实例率先改变状态,p
的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p
的回调函数。
下面是一个例子,如果指定时间内没有获得结果,就将 Promise 的状态变为reject
,否则变为resolve
。
const p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
]);
p
.then(console.log)
.catch(console.error);
//如果 5 秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数。
Promise 用法示例
// 封装一个ajax方法
const getJson=(url)=>{
let p = new Promise((resolved,rejected)=>{
const xhr = new XMLHttpRequest();
xhr.open("GET",url);
xhr.onreadystatechange = handler;
xhr.responseType ="json";
xhr.setRequestHeader("Accept","application/json");
xhr.send()
function handler(){
// console.log(this)
if(this.readyState==4){
if(this.status==200){
resolved(this.response)
}else{
// rejected(new Error(this.statusText))
rejected(new Error("数据为空"))
}
}
}
})
return p;
}
let p = getJson("https://api.apiopen.top/videoHomeTab");
p.then((res)=>{
console.log(res)
},(error)=>{
console.log(error)
})
集合
Set 集合
表示无重复数值的有序列表,不是键值对的形式存储
var set = new Set();
set.add(666);
set.add("哈哈");
set.add("张三");
set.add("张三");
set.add("张三");
set.add("张三");
console.log(set);//666 哈哈 张三
console.log(set.has(666));//是否有666 true
console.log(set.delete(222));//删除集合中的222 false 集合中没有222
set集合中 键就是值 值就是键 所以一般不用forEach遍历
set.forEach((v,k)=>{
console.log(k,v);
})
//666 666
//哈哈 哈哈
//张三 张三
可以使用for...of 遍历
for (const v of set) {
console.log(v);
}
//666
//哈哈
//张三
因为set集合为没有重复数值的有序列表,所以可以用来数组去重
let arr = [1,1,2,2,3,4,5,6,7,7]
let set = new Set(arr)//将数组转为set集合
console.log(set)//此时打印的set集合已经没有重复
var arr1 = [...set]//将set集合转为数组
console.log(arr1)//打印去重后的新数组
Map集合
Map集合是键值对的有序列表,键和值是任意类型
let haha = new Map();
//存值
haha.set("name","张三");
haha.set("age",10);
console.log(haha);
//Map(2) {'name' => '张三', 'age' => 10}
console.log(haha.get("name"));// 张三 获取name
console.log(haha.has("name"));// true 是否有name
console.log(haha.delete("name"));// true 删除name键值对
其他写法
let m = new Map([
["a",1],
["b",2]
]);
console.log(m);
//Map(2) {'a' => 1, 'b' => 2}
WeakMap()和WeakSet()
for...in
用于对象,for...of 用于所有可迭代对象
for...in 语句用于对象的属性进行循环操作。 其语法如下:
for (var k (变量名) in 对象名字) {//变量 == 对象中所有的属性名
console.log(对象名[k]) // 在此执行代码,ls[k] 为属性值
}
var obj = {a:1, b:2, c:3};
for (var prop in obj) {
console.log("obj." + prop + " = " + obj[prop]);
}
for...of
for...of
语句 在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句
const array1 = ['a', 'b', 'c'];
for (const element of array1) {
console.log(element);
}
// a
// b
// c
迭代器 Iterator
现在有数组、对象、Map、Set、四种数据组合,他们还可以互相嵌套。需要一个统一的接口机制,来处理所有的数据结构 遍历器(Iterator)就是这样一种机制
Iterator的作用有三个: 一是为各种数据结构,提供一个统一的、简便的访问接口; 二是使得数据结构的成员能够按某种次序排列; 三是ES6创造了一种新的遍历命令for...of
循环,Iterator接口主要供for...of
消费
var arr = ['a','b','c']
let it = arr[Symbol.iterator]();//人为创建迭代器
console.log(it.next());//创建迭代器后可以异步迭代
console.log(it.next());
console.log(it.next());
//注意:迭代器要用第三方变量接,不然每一次调用next()都相当于第一次调用
注意:有迭代器 Iterator 才能使用迭代 上面的代码人为创建了一个迭代器 下面的 keys() values() entries() 方法使用后自动创建了迭代器。可以直接迭代
1.迭代器是一个接口,能快捷的访问数据,通过Symbol.iterator来创建迭代器 , 通过迭代器的next()方法来获取迭代之后的结果. 2.迭代器是用于遍历数据结构的指针(数据库的游标)
keys() values() entries() 方法的使用:
let arr = [666,222,33,55];
let it = arr.keys();//使用keys()后数组有可迭代的接口(Interator接口),可以用来迭代
console.log(it);
console.log(it.next());//迭代
let it = arr.values();//使用values()后数组有可迭代的接口,可以用来迭代
console.log(it);
console.log(it.netx());//迭代
let it = arr.entries();//使用entries()后数组有可迭代的接口,可以用来迭代
console.log(it);
console.log(it.next());//迭代
Object.keys
Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致
Object.values
Object.values() 方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for...in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。
Object.entries
Object.entries() 方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)
var obj = {
name:'lishuo',
age:22
}
console.log(Object.entries(obj))
// ['name', 'lishuo']
// ['age', 22]
//返回为数组
var obj = {
name: 'lishuo',
age: 22
}
for (const [key, value] of Object.entries(obj)) {
console.log(`${key}: ${value}`);
}
// name: lishuo
// age: 22
//返回为字符串
生成器
generator 函数
generator函数,可以通过 yield 关键字键函数挂起(让函数停留在当前的位置) 为了改变执行流提供了可能,同时为了做异步编程提供了可能
genertor函数没有执行器,需要 next() 方法来调用。 generator函数的返回值是Iterator(迭代器)
1.function后面 函数名之前有一个 * 2.只能在函数内部使用yield表达式,让函数挂起
function* fun(){
console.log(111);//执行第一次
yield 1;//停止 1 为next()方法返回的value
console.log(222);//执行第二次
yield 2;//再次停止
console.log(333);//执行第三次
}
//调用的时候返回一个类似迭代器对象,可以调用next()方法
//generator函数分段执行的,yield是暂停执行,然而next()是恢复执行
var it = fun()//要用第三方变量接函数,不然每一次直接调用都为第一次调用
console.log(it.next());//111 {value: 1, done: false}
console.log(it.next());//222 {value: 2, done: false}
console.log(it.next());//333 {value: undefined, done: true}
//value为yield返回的值 done为函数是否运行结束
调用时利用 next () 传参
function* fun2() {
console.log("start");
let x = yield '第一次暂停';
console.log("第二个next传递的参数为:" + x);
let y = yield '第二次暂停';
console.log("第三个next传递的参数为::" + y);
}
let it = fun2();
console.log(it.next());//start {value: '第一次暂停', done: false}
console.log(it.next(10));//第二个next传递的参数为:10 {value: '第二次暂停', done: false}
console.log(it.next(30));//第三个next传递的参数为::30 {value: undefined, done: true}
//注意:x 不是 yield 的返回值 next 将参数传递给 yield 后赋给 x
使用场景 :
为不具备Interator接口的对象提供了遍历操作
// 使用场景 :为不具备Interator接口的对象提供了遍历操作
const obj = {
name: "张三",
age: 10
}
//1.创建新的迭代器
obj[Symbol.iterator] = objectEntries;
//2.搞一个generator函数
function* objectEntries(obj) {
//获取对象所有的key保存到数组[name,age]
const propkeys = Object.keys(obj);//使用keys方法使得obj可以被迭代
for (const propkey of propkeys) {
yield [propkey, obj[propkey]];
}
}
// 迭代器一旦生成我们就可以利用for of进行遍历了
for (let [key, val] of objectEntries(obj)) {
console.log(key, val)
}
// var it = objectEntries(obj);
// console.log(it.next());
// console.log(it.next());
// console.log(it.next());
生成器的应用
//搞一个生成器主函数main
function* main() {
let res = yield request("https://api.apiopen.top/videoHomeTab");//ajax获取数据
console.log(res);
}
// 调用函数
let it = main();
it.next()
// 封装一个请求接口的函数
function request(url) {
$.ajax({
type: "get",
url: url,
async: true,
success: function (res) {
it.next(res)
}
})
}
生成器AJAX案例
当页面未加载时展示UI 加载完成后展示另一个UI
客观请稍等正在加载数据
async 函数
async 函数实际上就是Generator 函数的语法糖(语法的简易写法)
async
函数就是将 Generator 函数的星号(*
)替换成async
,将yield
替换成await
,仅此而已。
例:
async function fun(){
// var err = new Error('出现错误');
// throw err;
return await "你好 async";
}
var p = fun()
p.then(res=>{
console.log(res);//若没有错误,在此打印
}).catch(err=>{//若出现错误,被catch捕捉
console.log(err);//在此打印错误
})
例:
function timeout(ms) {
return new Promise((resolve) => {//resolve在此处传递的是 Promise是否执行成功
// var err = new Error('运行出现错误')
// throw err;//当出现错误的时候,停止在下端await不继续执行
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);//await 在此做了同步化处理。若没有await使其等待,则会先执行打印
console.log(value);
}
asyncPrint('hello world', 2000);
async
函数内部return
语句返回的值,会成为then
方法回调函数的参数。
async
函数内部抛出错误,会导致返回的 Promise 对象变为reject
状态。抛出的错误对象会被catch
方法回调函数接收到。
正常情况下,await
命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。 上面代码中,await
命令的参数是数值"你好 async"
,这时等同于return "你好 async"
。
async
函数返回的 Promise 对象,必须等到内部所有await
命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return
语句或者抛出错误。也就是说,只有async
函数内部的异步操作执行完,才会执行then
方法指定的回调函数。`
async
函数对 Generator 函数的改进,体现在以下四点:
内置执行器 Generator函数执行必须靠执行器 next() ,而 async 函数自带执行器。可以像普通函数一样直接调用。
更广的适应性 co
模块约定,yield
命令后面只能是 Thunk 函数或 Promise 对象,而async
函数的await
命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
返回值是 Promise 对象 async
函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then
方法指定下一步的操作。
进一步说,async
函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await
命令就是内部then
命令的语法糖。
async
函数返回一个 Promise 对象,可以使用then
方法添加回调函数。当函数执行的时候,一旦遇到await
就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
Class 类
ES5创建构造函数
function Person(name,age){
this.name = name;//所有被构造函数创建的对象都会有的属性
this.age = age;
}
Person.prototype.say= function(){//通过原型链,可以给所有被创建的对象添加方法
console.log(`你好我是${this.name}`);
}
let xm = new Person("小明",10);
xm.say()
function Person(name,age){
this.name = name;
this.age = age;
this.say = function(){
console.log(`你好我是${this.name}`);//通过this创建的say方法只是构造函数拥有,构造函数创建的对象不拥有
}
}
let xm = new Person("小明",10);
xm.say()
Es6 通过类创建对象
class Student {
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(`你好我是${this.name}`);
}
skill(){
console.log(`${this.name}会打乒乓球`);
}
}
let zs = new Student("张三",30)//通过类创建的对象,可以直接使用 say() skill() 方法
let ls = new Student("李四",30)
zs.say();
ls.skill();
ES6 类的继承
使用关键字 extends继承
super 关键字用于访问和调用一个对象的父对象上的函数。
在构造函数中使用时,super
关键字将单独出现,并且必须在使用this
关键字之前使用。super
关键字也可以用来调用父对象上的函数。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
say() {
return `你好我是${this.name}`
}
}
class Student extends Person {
constructor(name, age, stId) {
super(name, age);//注意,在派生的类中,使用this前,必须先调用 super() ;这里调用父类的构造函数的,为派生类使用
this.stId = stId;
}
skill() {
console.log(`${this.name}会打乒乓球`);
}
}
let zs = new Person("张三",30);//父类创造的对象
let xm = new Student("小明",10,"12345678")//派生类创造的对象
console.log(zs.say());//父类创造的对象可以使用父类的方法
console.log(xm.say());//派生类创造的对象也可以使用父类的方法
xm.skill();//派生类使用自己的方法
ES5中的继承
1.//原型链继承
实现方式:将子类元素的原型链指向父类继承
function Parent(){
this.name = "parent";
this.list = ['a'];
}
Parent.prototype.sayHi = function(){
console.log('hi');//hi
}
function Child(){
}
Child.prototype = new Parent();
var child = new Child();
console.log(child.name);//parent
child.sayHi();
原理:子类实例child的__proto__指向Child的原型链prototype,而Child.prototype指向Parent类的对象实例,该父类对象实例的__proto__指向Parent.prototype,所以Child可继承Parent的构造函数属性、方法和原型链属性、方法
优点:可继承构造函数的属性,父类构造函数的属性,父类原型的属性
缺点:无法向父类构造函数传参;且所有实例共享父类实例的属性,若父类共有属性为引用类型,一个子类实例更改父类构造函数共有属性时会导致继承的共有属性发生变化;实例如下:
var a = new Child();
var b = new Child();
a.list.push('b');
console.log(b.list); // ['a','b']
2.构造函数继承
实现方式:在子类构造函数中使用call和apply劫持父类构造函数方法,并传入参数
function Parent(name, id){
this.id = id;
this.name = name;
this.printName = function(){
console.log(this.name);
}
}
Parent.prototype.sayName = function(){
console.log(this.name);
};
function Child(name, id){
Parent.call(this, name, id);
// Parent.apply(this, arguments);
}
var child = new Child("jin", "1");
child.printName(); // jin
child.sayName() // Error
原理:使用call或者apply更改子类函数的作用域,使this执行父类构造函数,子类因此可以继承父类共有属性
优点:可解决原型链继承的缺点
缺点:不可继承父类的原型链方法,构造函数不可复用
3.组合继承
原理:综合使用构造函数继承和原型链继承
function Parent(name, id){
this.id = id;
this.name = name;
this.list = ['a'];
this.printName = function(){
console.log(this.name);
}
}
Parent.prototype.sayName = function(){
console.log(this.name);
};
function Child(name, id){
Parent.call(this, name, id);
// Parent.apply(this, arguments);
}
Child.prototype = new Parent();
var child = new Child("jin", "1");
child.printName(); // jin
child.sayName() // jin
var a = new Child();
var b = new Child();
a.list.push('b');
console.log(b.list); // ['a']
优点:可继承父类原型上的属性,且可传参;每个新实例引入的构造函数是私有的
缺点:会执行两次父类的构造函数,消耗较大内存,子类的构造函数会代替原型上的那个父类构造函数
4.原型式继承
原理::类似Object.create,用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象,结果是将子对象的__proto__指向父对象
var parent = {
names: ['a']
}
function copy(object) {
function F() {}
F.prototype = object;
return new F();
}
var child = copy(parent);
console.log(copy(parent))//[[Prototype]]: Object names: ['a']
缺点:共享引用类型
5.寄生式继承:
原理:二次封装原型式继承,并拓展
function createObject(obj) {
var o = copy(obj);
o.getNames = function() {
console.log(this.names);
return this.names;
}
return o;
}
优点:可添加新的属性和方法
6.寄生组合式继承
原理:改进组合继承,利用寄生式继承的思想继承原型
function inheritPrototype(subClass, superClass) {
// 复制一份父类的原型
var p = copy(superClass.prototype);
// 修正构造函数
p.constructor = subClass;
// 设置子类原型
subClass.prototype = p;
}
function Parent(name, id){
this.id = id;
this.name = name;
this.list = ['a'];
this.printName = function(){
console.log(this.name);
}
}
Parent.prototype.sayName = function(){
console.log(this.name);
};
function Child(name, id){
Parent.call(this, name, id);
// Parent.apply(this, arguments);
}
inheritPrototype(Child, Parent);
模块
一个模块就是一个独立的JS文件 ES6的模块功能主要由两个命令构成: esport 暴漏 (抛出) 、 import()
在需要被暴漏的模块中:
let name = "李四";
let age = 10;
let add = (a,b)=>{
return a+b;
}
const content = {
name:"张三",
age:10,
add(a=0,b=0){
return a+b;
}
}
// 暴露(抛出)
export {name,age,add}//
export {content}
在引入模块的文件内: 注意:在引入模块的文件内,script 标签的 type = ‘module’ 不然会报错
//第一种写法
import {content,name} from "./modules/Module1.js";
console.log(name);//李四
//第二种写法
import * as f from './modules/Module1.js'
//任意命名 f , 暴漏的所有数据都在 f 对象内
//引用可以这样写:
console.log(f.name)//李四
注意:需要暴露什么写什么,需要接收什么写什么
ES5 中请求模块用 require
export default
export default
命令,为 模块 指定默认输出。
在需要被暴漏的模块中:
const name ="张三";
const age = 18;
const obj = {
name:"大豆"
}
export {name,age,sayName,Person,obj}
export default obj //此为默认输出
在引入模块的文件内:
import * as f from './modules/Module2.js'// f 为自定义命名
// console.log(f)
// f 内为 export 暴漏的所有数据
import a from './modules/Module2.js'// a 为自定义命名
console.log(a)
// a 内为默认暴漏的数据
SQL 语句
插入语句
INSERT INTO user (user_name,user_phone,user_psw) VALUES('康新洋','18220550304','123456')
插入在 user 表中 插入的键为 user_name , user_phone , user_pwd 插入的值为...
查询语句
SELECT * FROM `user`
SELECT * FROM user WHERE user_name='苏倩文'
SELECT * FROM `user` WHERE id = 5
查询名为 user 的数据库 查询 user 库中 user_name 为 苏倩文 的 查询 user 库中 id 为5 的
删除语句
DELETE FROM user WHERE id = 6
DELETE FROM user WHERE user_name = '赵阳'
更新 (更改)
UPDATE `user` SET `user_phone` = '18220550308' WHERE user_name='茹小龙'
设置新的手机号 在 user_name 为 如小龙的数据下
Node.js
需要安装Node环境。
在浏览器打开输入 localhost : 端口号 或 IP地址 : 端口号
创建服务器
//引入http模块
const http = require('http')
//此模块为Node.js 内置模块,无需下载
//设置访问域名
const hostname = 'locohost'
//设置端口
const post = 1225
//创建服务
const server = http.createServer((request, response) => {//request 为请求 ; response 为响应
//请求状态
response.statusCode = 200;
//设置请求头
response.setHeader('Content-Type', 'text/plain;charset=utf-8');//此处有编码方式 utf-8
//返回页面的数据
response.end('Hello World')//注意:end()中只能传字符串
//监听端口
}).listen(post,()=>{
console.log(`服务器运行在 http://${hostname}:/${post}`)
})
//运行此文件在 git 中输入 :
//node 文件名
//运行此文件为 node Node_1.js
//服务器代码改变后需要重启服务器才可生效
//运行结束后需要关闭服务器 快捷键 ctrl+c 或 JS中输入代码 process.exit(1);
const http = require('http');
//const mysql = require('mysql');
const server = http.createServer((req, res) => {
res.end('111')
//在此插入
}).listen(1226)
console.log('服务器成功执行')
http 模块中的 end() 方法传回的参数是传回到页面的
与数据库连接
此处为查询操作 if(req.url === "favicon.ico"){return};//阻止重复请求(放在服务器下)
//请求mysql模块
const mysql = require('mysql')
//mysql模块不是内置模块,在git中输入 npm install mysql -- save 下载模块
//创建链接(与sql)
const connection = mysql.createConnection({
//地址
host: 'localhost',
//sql的用户名密码
user: 'root',
password: 'root',
//数据库名
database: 'web2137',
multipleStatements:true // 支持执行多条 sql 语句
})
//链接
connection.connect();
//sql查询语句
let sql = 'select * from user'
//查询
connection.query(sql,(error,result)=>{
if(error){
throw error;
}
console.log(result);
// process.exit(1); //关闭服务器代码
})
//运行此文件前先打开阿帕奇与sql数据库
//运行此文件在 git 中输入 :
//node 文件名
//运行此文件为 node select_node.js
//运行服务器后需要关闭服务器 JS代码为 process.exit(1);
//或在git中 ctrl + c 关闭服务器
在git中输入 npm install mysql -- save 下载模块 mysql (npm为外网) 在git中输入 cnpm install mysql -- save 下载模块 mysql (cnpm为国内网站)
sql 模块中的 end() 方法为结束数据库操作
创建服务器并查询数据库
//引入模块
const http = require('http');
const mysql = require('mysql');
//创建服务器
const server = http.createServer((req, res) => {//req 为请求; res 为响应
//创建数据库链接
const connection = mysql.createConnection({
host: "localhost",//地址
//post: 1225,// 默认端口 可以不用设置
user: "root",
password: "root",
database: "web2137"//数据库名
})
//连接数据库
connection.connect();
//sql 查询代码
const sql = 'SELECT * FROM `user`'
//查询
connection.query(sql, (error, results) => {//参数为 错误 | 数据
if (error) {
throw error;
}
results = JSON.stringify(results);//end()中只能传入字符串,在此将数据转为字符串
//创建请求头
res.setHeader('Content-Type', 'text/plain;charset=utf-8');//res为服务器响应
res.end(results);
})
})
//监听端口
server.listen(1225);//参数还可加一个回调函数
console.log('成功')
在浏览器中打开: 地址 : 端口号 localhost : 1225 或 ip地址 : 端口号 (cmd中查询IP地址代码:ipconfig) 192.168.0.126 : 1225 引入 http 模块才可在浏览器中打开
封装模块
module.exports 对象是由模块系统创建的。在我们自己写模块的时候,需要在模块最后写好模块接口,声明这个模块对外暴露什么内容,module.exports 提供了暴露接口的方法
var app = {
name: 'app',
version: '1.0.0',
sayName: function(name){
console.log(this.name);
}
}
module.exports = app;//将app暴漏,可以调用模块
//调用方法
var app = require('./app.js');
app.sayName('hello');//hello
封装的db 数据库模块
const mysql = require('mysql');
module.exports = (sql,callback)=>{
const db = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
database : 'web2137'
});
db.connect();
db.query(sql,callback);
db.end();
};
get请求
const http = require('http');
const request = require('request');//需要下载模块
const server = http.createServer((req,res)=>{
const url = "https://v.juhe.cn/toutiao/index?type=caijing&key=c14887fe64c3c92f7cd9507b34e01257";//请求地址
request(url,(err,response,body)=>{//错误,请求,内容
if(!err && response.statusCode == 200){
// console.log(body);
res.setHeader('Content-Type', 'text/plain;charset=utf-8');
res.end(body);
}
})
});
server.listen(3000);
console.log(666);
post 请求
const post = require('request');
const http = require('http');
const server = http.createServer((req,res)=>{
post({
url:'http://v.juhe.cn/toutiao/index',
form:{
type:'yule',
key:"51c6425aff3ff156f7b2f8bac5496a71"
}
},(error,response,body)=>{
if(!error && response.statusCode == 200){
console.log(body);
res.setHeader('Content-Type', 'text/plain;charset=utf-8');
res.end(body);
}
});
});
server.listen(3000);
console.log(666);
get post 综合代码
get:
const http = require("http");
const db = require("./db");//db模块仍然为封装模块
const server = http.createServer((req,res)=>{
//设置允许所有资源跨域的头属性
res.setHeader("Access-Control-Allow-Origin", "*")
// console.log(req.url);
let wdata = udata(req.url);
console.log(wdata.user_name);
// 数据库的链接
let sql = ` SELECT * FROM user WHERE user_name='${wdata.user_name}'`;
db(sql,(err,results)=>{
if(err){
throw err;
}
results = JSON.stringify(results)
res.setHeader('Content-Type', 'text/plain;charset=utf-8')
res.end(results)
})
// 做一个简单的封装 ,哈哈我就把获取过来的数据当字符串处理了
function udata(str) {
// 注意要是有汉字做个简单的解码decodeURI(str)
str = decodeURI(str);
// 1.处理掉?
var dataStr = str.split("?")[1];
// 2.进行一个截取转化成数组
dataStr = dataStr.split("&");
// 3.定义一个新对象存放数据
var data = new Object()
// console.log(dataStr);
// 4.遍历每个数组对象处理成对象的key:val
dataStr.forEach(function(item) {
var it = item.split("=");
data[it[0]] = it[1];
})
return data;
}
})
server.listen(3000)
console.log(666);
post:
const http = require("http");
const db = require("./db");
const querystring = require("querystring");
const server = http.createServer((req,res)=>{
//设置允许所有资源跨域的头属性
res.setHeader("Access-Control-Allow-Origin", "*")
var str = "";
req.on('data',function(data){
str += data; //串联 data 数据
console.log(str);
});
//获取完所有数据后执行req.on(‘end’,function(){})
req.on('end',function(){
let json = querystring.parse(str);
console.log(json);
let sql = `INSERT INTO user (user_name,user_phone,user_pwd) VALUES('${json.user_name}','${json.user_phone}','${json.upassword}')`;
db(sql,(err,results)=>{
if(err){
throw err;
}
results = JSON.stringify(results)
res.setHeader('Content-Type', 'text/plain;charset=utf-8')
res.end(results)
})
})
})
server.listen(3000)
console.log(666);
尝试后发现,数据库的增删改查只是其中的sql语句发生了改变,所以将其余部分做个封装
封装部分 :
const mysql = require('mysql');
module.exports = (sql,callback)=>{
const db = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
database : 'web2137'
});
db.connect();
db.query(sql,callback);
db.end();
};
引用部分 :
const http = require('http');
const db = require('./fzmodule');
const server = http.createServer((req,res)=>{
// console.log(req,res);
//阻止多次发送请求
if(req.url == "/favicon.ico"){
return;
}
let sql = 'INSERT INTO user(user_name,user_phone,user_psw) VALUES("康新洋","18220550304","123456")';
db(sql,(err,results)=>{
if(err){
throw err;
}
results = JSON.stringify(results);
res.setHeader('Content-Type', 'text/plain;charset=utf-8');
res.end(results);
});
});
server.listen(3000);
console.log('666');
Express 框架
首先创建一个基础框架,同时参考菜鸟express安装教程与express官网安装教程安装
const express = require('express')//引用express模块(需要下载)
const app = express()//创建express对象
const port = 3000
//路由
app.get('/', (req, res) => {//访问localhost:3000 默认
res.end('123');
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
Express中 res.json 和res.end 及res.send()
用于快速结束没有任何数据的响应,使用res.end()。 响应中要发送JSON响应,使用res.json()。 响应中要发送数据,使用res.send() ,但要注意header ‘content-type’参数。 如果使用res.end()返回数据非常影响性能。 使用send发送中文数据就不用设置请求头写编码方式了
路由
路由决定了由谁(指定脚本)去响应客户端请求。 在HTTP请求中,我们可以通过路由提取出请求的URL以及GET/POST参数。
const express = require('express')//引用express模块(需要下载)
const app = express()//创建express对象
const port = 3000
//路由
app.get('/', (req, res) => {//访问localhost:3000 默认
let data = {
name:'aaa'
}
// res.end('123');
// res.send(data);
res.json(data);
})
//路由
app.get('/list',(req,res)=>{//访问localhost:3000/list
res.end('list')
})// /list 相当于访问地址
//路由
// 对页面 abcd, abxcd, ab123cd, 等响应 GET 请求
app.get('/ab*cd', function(req, res) {//正则请求
console.log("/ab*cd GET 请求");
res.send('正则匹配');
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
静态文件
Express 提供了内置的中间件 express.static 来设置静态文件如:图片, CSS, JavaScript 等。
app.use('/public', express.static('public'));// /public为静态文件的访问路径
get 接口
get接口中res.query为所有传入的数据
const express = require('express');
const app = express();
app.use('/public', express.static('public'));
app.get('/',(req,res)=>{
let data = {
name:'aaa'
}
// res.end('123');
// res.send(data);
res.json(data);
})
app.get('/list',(req,res)=>{
res.end('list');
})
//接口
app.get('/huoqu',(req,res)=>{//接口地址为/huoqu
// let data = req.query
let user_name = req.query.user_name;
let user_psw = req.query.user_psw;
let data = {
user_name:user_name,
user_psw:user_psw
}
res.send(data);
});
app.listen(3000);
console.log(666);
传输网页为
Document
post 接口
post 接口中 res,body 为所有传入的数据
const express = require('express');
const app = express();
app.use('/public', express.static('public'));//静态文件地址
var bodyParser = require('body-parser');//引入编码模块
// 创建 application/x-www-form-urlencoded 编码解析
var urlencodedParser = bodyParser.urlencoded({ extended: false })
//post接口
app.post('/denglu', urlencodedParser, function (req, res) {
res.send({
code:1,
msg:'登陆成功',
user_name:req.body.user_name,
user_psw:req.body.user_psw
});
// 输出 JSON 格式
// var response = {
// "first_name":req.body.first_name,
// "last_name":req.body.last_name
// };
// console.log(response);
// res.end(JSON.stringify(response));
})
app.listen(3000);
console.log(666);
html部分
post请求
热启动
npm install -g nodemon //安装
nodemon index.js //热启动 index.js
解决跨域
// 解决跨域问题
app.all("/*", function(req, res, next) {
// 跨域处理
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", ' 3.2.1');
res.header("Content-Type", "application/json;charset=utf-8");
next(); // 执行下一个路由
})
放在 app.js 文件内 所有的路由都不会跨域 放在单独的路由文件内,只有该文件内的路由不会跨域
app.use((req, res, next) => {
//设置请求头
res.set({
'Access-Control-Allow-Credentials': true,
'Access-Control-Max-Age': 1728000,
'Access-Control-Allow-Origin': req.headers.origin || '*',
'Access-Control-Allow-Headers': 'X-Requested-With,Content-Type',
'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS',
'Content-Type': 'application/json; charset=utf-8'
})
req.method === 'OPTIONS' ? res.status(204).end() : next()
})
支持get | post请求的接口
//登录接口接收所有请求,支持get post
router.all('/login', function(req, res, next) {
let odata;
if(Object.keys(req.query).length == 0){//判断使用的是什么请求
odata = req.body;//get请求为空时,odata为post请求的数据
}else{
odata = req.query;
}
res.send(odata);
});
验证码发送
新创建的模块 ( maileConfig.js ) 内nodemailer 模块需要下载
// 准备:进入邮箱:设置>账户>POP3/SMTP服务(开启之后记得复制密钥)
//nodemailer.js
const nodemailer = require('nodemailer');//该模块需要下载
//创建一个smtp服务器
const config = {
host: 'smtp.qq.com',
port: 465,
auth: {
user: '[email protected] ',//开发者邮箱
pass: 'xrchxszowsdubabe',//开发者密钥
}
};
// 创建一个SMTP客户端对象
const transporter = nodemailer.createTransport(config);
//发送邮件
module.exports = function (mail){
transporter.sendMail(mail, function(error, info){
if(error) {
return console.log(error);
}
console.log('mail sent:', info.response);
});
};
index.js 接口部分
var express = require('express');//下载express框架
const { send } = require('express/lib/response');
const maileConfig = require("./maileConfig");//自定义模块
const db = require("../db/db");//自定义模块
const LocalStorage = require('node-localstorage').LocalStorage,//下载localstorage模块
localStorage = new LocalStorage('./scratch');//创建localstorage对象
var router = express.Router();//创建router对象(框架内置)
router.use((req, res, next) => { //设置请求头解决跨域
res.set({
'Access-Control-Allow-Credentials': true,
'Access-Control-Max-Age': 1728000,
'Access-Control-Allow-Origin': req.headers.origin || '*',
'Access-Control-Allow-Headers': 'X-Requested-With,Content-Type',
'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS',
'Content-Type': 'application/json; charset=utf-8'
})
req.method === 'OPTIONS' ? res.status(204).end() : next()
})
//默认主页内容接口
router.get('/', function(req, res, next) {
res.send({
title:'express'
});
});
// 发送邮件的接口
router.get('/email', function (req, res, next) {
//保存验证码和邮箱,时间
let student = {};
let email = req.query.email;
let code = createSixNum();
console.log(code);
let time = new Date().getTime();
student.initCode = code;
student.time = time;
student.email = email;
student = JSON.stringify(student);
// 放入缓存中
localStorage.setItem(email,student)
let sql = `select * from student where email= "${email}"`;
db(sql, (err, data) => {
if (data.length) {
res.send({
code: 0,
message: "邮箱已注册"
})
} else {
var mail = {
// 发件人
from: '<[email protected] >',
// 主题
subject: '验证码',//邮箱主题
// 收件人
to: email,//前台传过来的邮箱
// 邮件内容,HTML格式
text: '用' + code + '作为你的验证码'//发送验证码
};
maileConfig(mail)
res.send({
code: 1,
msg: "发送成功"
})
}
})
// 随机产生六位验证码
function createSixNum() {
var Num = "";
for (var i = 0; i < 6; i++) {
Num += Math.floor(Math.random() * 10);
}
return Num;
}
});
//验证码校验(注册)
router.post("/jiaoyan", (req, res) => {
let obody = req.body;
// 获取缓存
let student = localStorage.getItem(obody.email)
console.log(student);
student = JSON.parse(student);
const registerTime = new Date().getTime()
if (registerTime - student.time >= 5 * 1000 * 60) {
res.send({
code: -1,
msg: '验证码已过期'
})
}
// console.log(student);
// console.log(obody);
if (student.initCode === obody.code) {
let sql = `INSERT INTO student (name,email,password) VALUES('${obody.name}','${obody.email}','${obody.password}')`;
db(sql,(err,data)=>{
res.send({
code: 1,
message: "注册成功",
data:data
})
})
// 注册成功删除缓存
localStorage.removeItem(obody.email);
console.log("----------------------");
console.log(localStorage.getItem(obody.email));
console.log("----------------------");
}
else {
res.send({
code: 0,
message: "验证码输入错误"
})
}
})
module.exports = router;
gitee 操作
文件操作: git pull // 将云端的文件从新下载到本地 git clone 项目地址 // 将仓库文件夹克隆到本地 mkdir 文件名 // 创建文件夹 cd 文件名 // 进入文件 cd ../ // 返回上一级 git pull --rebase origin master // 同步云端仓库和自己的仓库
上传操作: git add . // 选择当前文件夹内的所有文件 git commit -m " first commit " // 使文件上传到缓存区,备注(first commit) //上传如果报错 在这一步后加一步同步 git push -u origin master // 上传到git中