MD 语法
链接
[淘宝网](http://www.taobao.com/)
图片
![图片标题](file:///Users/wangjing/Desktop/511542077195.jpg)
标题
# 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题
tips:几个 # 就是几级标题,最小到六级
斜体
*这是斜体*
*[这是斜体链接](http://www.taobao.com)*
*斜体,[这是斜体链接](http://www.taobao.com)*
tips:斜体和链接可以混用
为字体加颜色
这是<label style="color:red">红色</label>字体
这是<label style="color:green">绿色</label>字体
这是<label style="color:yellow">黄色</label>字体
这是<label style="color:blue">蓝色</label>字体
为字体加粗
**加粗**字体
Email:<yabing.zyb@alibaba-inc.com>
无序排列
* list1
* list2
* list3
有序排列
1. list1
2. list2
3. list3
分割线
***
---
- - - -
tips: 三种都一样
内容框
在上一行内容缩进的基础上再缩进四个空格
换行
需要换行<br>这是换行后的下一行
中划线
~~中划线~~
添加脚注
这是脚注[^1]
[^1]: 这是脚注说明,会在文章的末尾显示.
表格
默认表格:
First Header | Second Header | Third Header
------------ | ------------- | ------------
Content Cell | Content Cell | Content Cell
Content Cell | Content Cell | Content Cell
左右浮动表格:
First Header | Second Header | Third Header
:----------- | :-----------: | -----------:
Left | Center | Right
Left | Center | Right
tips:默认向左对齐
内容块
> 这里的内容在内容块中
命令行
MAC终端命令
命令 | 执行 | 注释 |
---|---|---|
clear | 清空屏幕的内容 | |
pwd | 查看我们所在的目录(位置),刚打开终端的时候,默认在用户目录下。 | percent work directary |
ls | 显示当前目录下的文件内容,ls后面如果什么都不加,默认显示当前目录下的内容。ls 可以和路径配合使用,用于显示路径下的内容 | list show |
ls / | 显示跟目录下的内容 | |
ls ./ | 查看当前目录下得内容 | |
ls …/ | 查看父目录下得内容 | |
ls ~ | 查看用户目录的内容(打开终端默认在用户目录下) | |
ls -l | 会以一个列表的形式,把所有的内容全部输出出来 | |
ls -a | 看隐藏的文件 | |
ls -la | -l和-a的组合 | |
cd xxx | 进入xxx的文件夹(Tab键会自动补齐) | come directory |
cd - | 回到上一个目录 | |
cd ~ | 回到用户目录(刚打开终端时的目录) | |
/ | 根目录 | |
./ | 当前目录 | |
…/ | 上一级目录 | |
mkdir xxx | 在当前目录下,创建一个xxx名字的文件夹 | make directory |
mkdir a b c d | 新建多个文件夹 | |
mkdir -p res/style/scss | 新建多个层级的目录 | |
touch aaa | 在当前目录下创建一个aaa名字的文件 | |
rm 1.txt | 删除名字为1.txt的文件 | remove |
rm -rf 456/ | 删除当前目录下456名字的文件夹,删除文件夹的同时,里面的文件统统删除。 | |
mv 1.txt 123.txt | 移动+改名,将当前目录的1.txt 移动到当前目录,并改名为123.txt | move |
cp 1.txt 2.txt | 将当前目录下的1.txt拷贝一份,并放到当前目录下,并命名为2.txt | |
open . | 打开当前所在的文件夹 | |
open xxx/xxx | 打开指定路径文件 | |
mdfind name.html | 查询指定文件的路径 |
命令行vi (vim)
vi 1.c (如果文件存在,则打开这个文件,如果不存在,先创建,再打开)
vi 命令有3种模式
- 命令模式 (以:打头的命令)
:q 退出,(如果文件已经被编辑了,而没有保存的话,是无法退出的)
:w 保存
:wq 保存退出
:q! 不保存退出
:set nu 显示行号
:set nonu 隐藏行号 - 编辑模式
由编辑模式进入一般模式,按Esc键 - 一般模式 (一般命令)
由一般模式进入编辑模式
a,i,o, shift+a,shift+i,shift+o键dd 删除一行(光标所在的那一行) (剪切) 5dd 删除光标下的5行 p 粘贴 yy 复制 5yy 复制5行 u 撤销上一次操作 (undo) ctrl+r 恢复操作 (redo) gg 将光标定位在第一行 shift+g 将光标定位到最后一行 num shift+g 将光标定位在第num行
HTML
Hyper text makup language (超文本标记语言)
html结构
<!doctype html>
<html>
<head>
<meta charset="UFT-8">
<meta name="keywords" content="关键字,关键字">
<meat name="description" content="网页描述"
<link href="图标路径" rel="icon">设置网页图标单标签
<title>标题</title>
<style>
/*注释标签*/
</style>
</head>
<body>
<!--注释标签-->
<hr>横线单标签
<br>换行单标签
<img src="设置图片路径" width="" height="" alt="当图片无法显示时的描述行文字" title="设置鼠标悬停在图片上时的文字提示">图片单标签
<h1>-<h6>标题标签
<p>段落标签
<font size="16" color="red"></font>改变文字大小颜色
<u><ins>下划线标签
<del><s>删除线标签
<b><strong>加粗标签
<em><i>文字倾斜标签
</body>
</html>
路径
绝对路径
- D:/user/photo/1.jpg
- www.baidu.com
相对路径
(所有文件在同一个根目录里面)
- 如果图片和文件在同一个文件夹中,直接写图片名称< img src="1.jpg">
- 如果图片在文件的上一级目录中,写../图片名称 < img src="../1.jpg">
- 如果图片在文件的下一级目录中,写文件夹名称/图片名称< img src="images/1.jpg">
超链接
<a href="跳转目标页面的路径" target="_self(在当前标签打开目标页面) / _blank(在新标签中打开目标页面)">
锚链接
<!-- 在同一页面跳转到id指定位置 -->
<a href="#id值">
特殊字符
  空格
< <
> >
© ©️
列表
无序列表
<ul>
<li></li>
</ul>
有序列表
<ol>
<li></li>
</ol>
自定义列表
<dl>
<dt>标题</dt>
<dd>标题项</dd>
<dd>标题项</dd>
</dl>
表格
<table border="1" witdh="表格宽" height="表格高" cellpadding="内容和表格的间距" cellspacing="单元格间距" border-collapse:collapse;
align="表格对齐方式">
<caption>表格名称</caption>
<tr align="行内容对其方式">
<th colspan="横向单元格合并" rowspan="纵向单元格合并"></th>
<th></th>
<th></th><!--合并n个删除n-1个单元格-->
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
表单控件
<form action="提交的目标,例如1.php" method="提交的方式,有get/post两种">
<lable for="id名">输入框</lable(行内元素,配合for实现对应鼠标焦点)>
输入框<input type="text" name="设置输入框名字" value="设置默认值" maxlength="设置最大输入长度" readonly="readonly(设置只读)" id="id名" placeholder="占位符,为控件设置提示">
box-sizing:border-box; 设置这个属性后,设置元素宽高就是元素实际大小
密码框<input type="password">
复选框<input type="checkbox" checked="checked(默认选中)">
单选框<input type="radio" name="只有相同name值才能实现单选" checked="checked(默认选中)">
下拉列表<select>
<optgroup label="中国区域">
<option>北京</option>
<option selected="selected(默认选中)">上海</option>
</optgroup>
</select>
选择文件上传控件<input type="file">
文本域<textarea ></textarea>
数据提交按钮<input type="submit">
图片样式提交按钮<input type="image" src="按钮.jpg">
重置按钮<input type="reset">
按钮<input type="button" value="按钮">
</form>
标签分类
H5新增标签
/<header></header> 头部区域
/<nav></nav>导航区域
/<article></article>文章区域
/<aside></aside>侧边区域
/<section></section>块区域
/<footer></footer>底部区域
/<video src="路径" autoplay(自动播放,谷歌不支持) controls(显示控件) loop(循环播放)></video>视频播放
<video controls> 兼容写法
<source src="test.mp4">
<source src="test.avi">
</video>
<audio></audio>音频播放
<input type="email" name="">请输入邮箱地址
<input type="url" name="">请输入网址
<input type="number" name="" step="设置减少和增加的步数"> 只能输入数字
<input type="text" autofocus(自动获取焦点) required(控件内容不能空)>
<input type="date" name="" >日
<input type="month" name="">月
<input type="week" name="">周
<input type="range" name="">滑块
<input type="color" name="">拾色器
下拉列表
<input type="text" name="" list="abc">
<datalist id="abc">
<option>北京</option>
<option>上海</option>
<option>广州</option>
</datalist>
块级元素
独占一行,可以设置宽高,不设置宽的时候和父级元素宽相同 display:block;
div p h1-h6 ul ol li dl dt dd tr
行内元素
在一行显示,不能设置宽高 display:inline;
span a font strong em i
行内块元素
在一行显示,可以设置宽高 display:inline-block;
img input
伪元素
元素就是html标签,通过css模拟一个html标签叫伪元素(伪元素是行内素)
一个标签中最多设置两个伪元素
.box::before { before是标签在父级容器.box里元素的最前面
content:"内容区域";
}
.box::after { after是标签在父级容器元素的最后面
content:"";
}
标签包含规范
段落标签不能包含标题标签
段落标签不能包含div
不推介使用行内元素包含块级元素
css
层叠样式表(cascading style sheets)
css特性
层叠性:同一选择器的相同样式属性,后面覆盖前面
继承性:子元素未设置的属性(color / font所有属性 / )可以从父元素继承 【width / height 没有继承性】
优先级:!important (10000) > 行内样式(10000) > id选择器(1000) > 类选择器(100) > 标签选择器(10) > 继承(0)
css属性
文本
text-align:center; 元素水平居中
text-indent:2em;首行缩进
text-decoration:none/underline; 设置下划线
text-shadow:0px 0px 10px red,5px 5px 10px blue【左右偏移 上下偏移 模糊度 颜色】; 设置文字影阴
vertical-align:; 设置在垂直方向的对齐方式;
A.解决行内块元素底部3像素空白(vertical-align:baseline;行内块元素默认属性)
一种将行内块转换成块
第二种vertical-align:top(顶线对齐) / bottom(底线) / middle(中线); 【baseline:基线对齐】
B.解决图片垂直居中
先设置行高等于盒子高度再让图片中线对齐;
字体
font-size:14px;
font-weight:700(bold) 400(normal);
font-style:italic normal;
font-family:“宋体”;
line-height:24px;行高(只对文字有作用,行高等于容器高度文字局中)
list-style:none; 去掉列表默认样式
font:700 italic 14px/24px "宋体";
*合写必须设置font-size和font-family,font-size必须在font-family之前,font没有color属性*
背景
backgroun-color:red #222 rgb(100,100,255) rgba(0,0,0,0.1) *a:alpha 通道透明度0-1*;
background-image:url(“2.png”);
background-repeat:repeat / no-repeat / repeat-x / repeat-y; 设置背景图平铺方式(默认平铺)
background-size:200px 100px;(宽 高 背景图尺寸)
Background-size :cover(等比例将父元素铺满)/content(完整显示到父元素中);
background-position:left top / 20px 80px; (左正右负 下正上负)
设置背景图片位置 (left right top bottom center)
【设置两个值:宽 高;设置一个值,后面一个值默认center】
background:transparent(透明色) url("2.png") no-repeat 20px 80px; 背景合写没有个数和顺序限制
box-shadow:inset 5px 5px 5px blue;(盒子影阴,inset设置内影阴)
background:url(img.png) no-repeat left top, url(img.png) no-repeat left bottom;
background-attchment:fixed;(背景图附着)
Background-origin:border-box/padding-box/content-box;(背景图从什么位置开始显示)
background-clip:border-box/padding-box/content-box/text;(背景图从什么位置开始裁切)
渐变
线性
div{
background-image:linear-gradient(
to left,to right,to top,to bottom, /*方向到哪*/
0deg,45deg,90deg,135deg,180deg.../*0从y轴下开始,顺时针*/
red 20%, /*色块位置*/
blue 50%
);
background-sizing:200px 80px; /*设置这个后百分比相对于这个宽*/
}
径向渐变
<style>
div{
background-image:radial-gradient(
circle /*默认渐变是椭圆,加这个圆形渐变*/
100px(半径) at 100px 100px(圆心位置),
red 20%, /*色块位置*/
blue 50%
)
background-sizing:200px 80px; /*设置这个后百分比相对于这个宽*/
}
</style>
隐藏
opacity:0.5;(这种透明方式会让标签本身和内容都改变)
overflow:hideen; 超出父元素隐藏
overflow:scroll; 设置滚动条;
overflow:auto; 自动判断是否需要添加滚动条;
overflow:visible; 元素超出父级,没有滚动条,超出部分也正常显示。
display:none; 元素隐藏,隐藏后不占位置;
display:block; 显示元素。
visibility:hidden; 元素隐藏,隐藏后占位置(清除浮动会用);
text-overflow:clip(修剪文本)/ellipsis(省略号代替修剪的文本)/string(用指定字符串代替修剪的文本);(和overflow:hidden; 还有white-space:nowrap;)
* console——escape(“宋体”)查看字体编码
* em:一个相对单位(一个字符大小)
设置鼠标样式
cursor:move/pointer;
css书写位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>表单加表格</title>
<link rel="stylesheet" type="text/css" href="css文件路径"> 外链式
<style type="text/css"> 嵌入式
</style>
</head>
<body>
<p style="属性:值;属性:值;"></p> 行内式
</body>
</html>
css选择器
属性选择器: div[class]{} 有class属性的所有div
[class^="o"]{} 类名以字母o开始
[class$="o"]{} 类名以字母o结束
[type*="checkbox"]{} 属性里面有checkbox的type标签
[class][id="one']{}有id名是one并有class类名
标签选择器:p {}
类选择器:. 类名 {} <p class="类名1 类名2"></p>
*注意:不能以数字开头,不能以特殊符号开头,不要用汉字命名*
id选择器:#id名 {} <p id="id名"></p>
*一个标签只能调用一个id选择器,一个id选择器只能对应一个标签*
通配符选择器:* {} 选中页面中所有标签
后代选择器 :ul li {} 选中ul标签中所有的后代li标签
子代选择器:ul>li {} 选中ui标签下第一代li标签
指定选择器:ul.one {} ul#two{} <ul class="one"></ul>
并列选择器:ul,p, div {} 同时改变这些标签的属性
伪类选择器: :link {} 设置链接的样式(不推荐使用,有兼容性)
:visited {} 设置被访问过的标签样式(不推荐使用,只能设置颜色,有缓冲问题)
:hover {} 设置鼠标悬停在标签时的样式
:active {} 设置标签被激活的样式
:focus {} 设置获取鼠标焦点的样式 input:focus{color:red;}
结构伪类选择器:nth-child(n){} 选中父元素中第n个子元素
:nth-last-child(n){} 选中父元素中倒数第n个子元素
:first-child {} 选中父元素中的第一个子元素
:last-child {} 选中父元素中的第最后一个子元素
ul li:nth-child(5n) {} 选中父元素中是5的倍数的li
p:nth-of-type(n) 只读p的第n个
:nth-child(even偶数/odd奇数)
p:empty 读取空的p
盒子模型
盒子模型组成:内容区域,边框(border),内边距(padding),外边距(margin)
注意: <div style="width:300px; height:40px;"></div> 这里的宽高是指盒子内容区域的宽高
盒子实际大小=内容宽高+内边距+边框+外边距
box-sizing:border-box(自动计算)/content-box(默认计算方式);
border
border-style: none / solid / dashed / dotted;
border-width: 边框粗细;
border-color:边框颜色;
border-collapse:collapse; (表格边框合并)
border:5px solid red;(边框合写)【border-top / border-left / border-bottom / border-right】
border-radius:50%;
Border-radius:20px 20px 20px 20px(4个角水平半径) / 20px 20px 20px 20px(垂直半径);
如果垂直半径和水平半径一样可以省略不写垂直半径,如果四个角半径一样,可以只写一个。
去掉表单控件轮廓线:outline-style: none; 【这里轮廓线是🈯️鼠标点击后的蓝色轮廓】
边框图片设置
Border-image-source:url('img.png');
Border-image-slice:20 20 20 20; //切割图片,上右下左
Border-image-repeat:round; //设置切割后图片平铺方式
Border-image-width:20px; //设置边框图片宽度;
相邻盒子边框合并
让两个盒子浮动,边框通过margin-left:-1px;合并,然后鼠标经过给相对定位提高层级。
padding
加内边距后,盒子会变大,要保持盒子大小,需相应减少盒子内容区域的宽高。
padding:10px 20px 30px 40px; (上 右 下 左)
padding:10px 20px 30px; (上 左右 下)
padding:10px 20px; (上下 左右)
margin
写法同padding
Margin:0 auto; 只会让标准流下的盒子居中,auto只有块级元素才可以生效。
塌陷
外边距塌陷:
1.上下两个盒子,上面设盒子置下外边距,下面盒子设置上外边距,这两个外边距会以较大的那个外边距合并;
解决方式:只设置一个盒子的外边距。
2.两个嵌套盒子,设置margin-top,这两个margin-top会以较大那个外边距塌陷(这个猜测本质原因是基线重合)
解决方式:
1.给大盒子加1像素外边距或者1像素padding;
2.给父级元素加overflow:hidden;
3.浮动
清除样式
Body,h1,h2,h3,h4,h5,h6,ul,ol,li,dl,dd,dt,a {
margin:0;
padding:0;
list-style:none;
text-decoration:none;
}
浮动float
标准流就是网页标准
float:left /right
元素设置浮动后不占位置了
浮动有隐藏的行内转换属性
清除浮动
1.额外标签 clear:both; 在浮动元素同级加一个空元素,给clear属性2.overflow:hidden; 给浮动元素父级添加overflow属性 (使用该属性时,必须保证父元素中没有超出父元素的元素)
3.伪元素清除浮动【.clearfix{ *zoom:1; (加*号意思只有ie7以下浏览器解析)}】
4.双伪元素清除浮动
什么时候需要清除浮动
1.网页布局中,父元素没有设置高
2.父元素中,所有子元素都设置了浮动
注意:一个盒子里有两个子盒子,第一个盒子占位后,第二个盒子不管是浮动还是定位只是它本身不占位置,不会飘在第一个盒子上面。
定位
静态定位
( position:static;)
静态定位的元素就是标准流的默认位置
静态定位不能改变元素位置
绝对定位
position:absoulte;
绝对定位可以改变元素位置;
绝对定位的元素会以有定位的父元素为参照物,如果父级没有,会参body;
绝对定位的元素是脱标元素,不占位置,行内元素设置绝对定位后可以设置高;
绝对定位居中
<div class="box1"> /.box1{position:relative;}
<div class="box2"></div>
/.box2{position:absoulte; left:50%(父元素); margin-left:box2宽度一半;}
</div>
相对定位
position:relative;
相对定位可以改变元素位置
相对定位以自己的位置为参照物
相对定位元素不会脱标,占位置。(子绝父相)
固定定位
position:fixed;
固定定位可以改变元素位置;
固定定位元素始终以浏览器html为参照物
固定定位的元素也是脱标元素,不占位置;
定位层级关系
只有相对定位/绝对定位/固定定位的元素才有层级
z-index:;值越大层级越高,值相同,后面压前面
如果父元素有层级,那么比较父元素层级,不用比较子元素层级
精灵图
减少服务器请求次数,提高加载效率。插入背景图定位。
图标字体
iconfont.cn icomoon.io
图片垂直居中
1.这种盒子高度改变,图片就不居中了
text-align=center; ling-height=盒子高; vertical-align=middle;
2.插入一个空标签,html结构臃肿
<div>
<img src="">
<span></span>
</div>
div{
设置宽高
text-align:center;
}
span {
display:inline-block;
vertical-align:middle;
height:100%;
}
img {
vertical-align:middle;
}
3.用伪元素来让图片垂直居中
div::before {
content:"";
height:100%;
width:0;
display:inline-block;
}
img {
vertical-align:middle;
}
css3
过渡(补间动画)
transition 【需要用户动作才能执行】
语法:
transition-property:all; 默认值是all(代表开始状态和结束状态有状态差的所有属性都有动画效果。)[必须有]
transition-duration:1s; (完成动画需要的时间) 【必须有】
transition-delay:2s; (延时执行动画)
transition-timing-function:ease,linear, ease-in,ease-out,ease-in-out; 默认值是ease (速度类型)
transition:all 1s linear;
transition: width 1s ease,height 1s ease 2s;
动画(补间动画)
animation【不需要用户动作就能执行】
语法:
调用并执行动画集
animation:
animation-name函数名
animation-duration动画完成一个周期花费的时间
animation-iteration-count:1;设置执行次数 /*默认1次,infinite无限循环*/
animation-timing-function:linear;动画速度类型;
animation-direction:alternate;设置动画是否在下一周期逆播,默认是normal(恢复开始状态也有动画,当动画执行次数为偶数有逆播效果)
animation-delay:2s;设置动画延时
animation-play-state:paused;设置动画运行或暂停(默认是running)
animation-fill-mode:forwards(动画结束后停在结束状态);设置动画执行完成后的状态,回道开始状态backwards
steps(多少步完成1周动画);步
定义动画集
@keyframes 函数名 {
from{ /*用from to或者百分比来表示动画的开始结束状态*/
开始状态
}
to { /*百分比相对于动画执行时间*/
结束状态
}
}
2D和3D转换
transform
语法:
旋转
transform-origin:left top; (旋转起始点,可以是像素)[3d里面改变旋转轴]
transform:rotate(60deg); (旋转的度数,正数为顺时针,负数为逆时针)
3D合写要用rotate3d();
【先旋转后位移的时候一定要注意旋转后的轴变了】
缩放
transform:scale(0.5,2); ( x轴,y轴。大于1放大,小于1缩小,取值为0的时候,元素宽高为0;)[放大会让元素里的元素内容都放大]
倾斜
transform:skew(30deg,50deg);
位移
Transform:translate(Xpx,Ypx);
transtorm:translate(100%,50%); 百分比相对于元素自身宽高
合写
transform:translateX(10px) translateY(20px) scale(1) rotateX(10deg) rotateY(20deg)
Transform-style:preserve-3d; (申明这是一个3D的盒子)
perspective:推介600-1000px; 浏览器近大远小透视效果;
私有前缀(了解)
浏览器厂商通常都是在属性名称前添加厂商的私有前缀,来测试这些尚未成为标准的特性, 因此,可以借助私有前缀,来解决浏览器对CSS3的兼容性问题。
内核 | 前缀 | 主要浏览器 |
---|---|---|
Trident | -ms- | Internet Explorer |
Gecko | -moz- | Firefox |
Webkit | -webkit- | Chrome、Opera、Safari、Android |
Presto | -o- | 早期Opera |
.box{
-webkit-transition:all 1s;
-moz-transition:all 1s;
-ms-transition:all 1s;
-o-transition:all 1s;
transition:all 1s;
}
/推荐使用 先前缀后标准 顺序/
移动Web
基础知识
移动端适配基础知识
获取设备独立像素(物理像素比)
alert(window.devicePixelRatio)
- 物理像素
当前设备的实际宽度和高度【固定,由电脑硬件决定】; - css像素
通过css设置的宽度和高度【受设备密度和浏览器窗口大小决定】 - 视口(viewport)
用来约束网页中最顶级块元素html的大小;
pc端视口大小就是浏览器窗口的大小;
移动端网页布局不受视口大小影响,移动端有默认视口大小,通常是980px; - word-break属性介绍
> 该属性规定自动换行的处理方法。
>
> normal (按照浏览器默认的换行方式) | break-all | break-all
> ```
- 设置文字超出以省略号隐藏显示
```css
//注意:要设置宽,不能有高,有高第三行会露出一点
overflow:hidden;
word-break:keep-all; 段落文字有空格就换行;
word-break:break-all; 段落文字在容器末尾换行
text-overflow:ellipsis;文字超出容器显示省略号
-webkit-line-camp:2;文字要显示多少行
/* autoprefixer: off */
-webkit-box-orient: vertical;
/* autoprefixer: on */
display:-webkit-box;将盒子转换为弹性盒子
less(css预处理器,需要node环境)
在服务器环境下,可以直接引用less文件
1. HTML页面直接通过link标签引用 less文件
<link rel="stylesheet/less" type="text/css" href="index.less>"
2. HTML页面中引用用来解析less文件的一个js文件
<script type="text/javascript" src="less.js"></script>
用less引入样式在index.css
@import 'base.css';
@import "shipei.css";
/*声明变量*/
@bgc:red;
@size:14px;
p{
background:@bgc;
font-size:@size*2;//支持计算
.punlic(100px,200px, red);//调用公共样式
}
/*定义函数公共样式*/
.public(@a,@b,@c){
width:@a;
height:@b;
background:red;
color:@c;
}
/*有默认值的函数公共样式*/
.public(@a:100px,@b:200px,@c:red){
width:@a;
height:@b;
background:red;
color:@c;
}
/*嵌套写法*/
div{
width:200px;
a {
font-size:100px;
}
}
对应生成的css是
div a {
font-size:100px;
}
屏幕适配
流式布局(百分比)
- width=100%;【任何设备网页宽度等于浏览器宽度】
- 任何设备内容不缩放
- width=device-width 宽度等于当前设备宽度,满足多个终端
- initial-scale=1 不缩放
- user-scalable=0 禁止用户缩放
- maximum-scale=1.0 最大缩放比例
- minimum-scale=1.0 最小缩放比例
<meat name=‘viewport’ content=“width=device-width,initial-scale=1,user-scalable=no>
//快捷键 meat vp
伸缩布局(flex)
- display:flex; 设置父级盒子为伸缩盒子
- 当父级盒子为伸缩盒子时,子元素在父级中一行显示(沿主轴排列)
在伸缩盒子中有两条轴
主轴默认水平显示,侧轴垂直
flex-direction:row;(主轴默认值水平)
flex-direction:column;(主轴垂直显示)
flex-direction:row-reverse;(主轴水平反向)
flex-direction:column-reverse;(主轴垂直反向)
- 子元素在主轴的对齐方式
justify-content:flex-statr;(默认)
justify-content:flex-end;(右侧对齐)
justify-content:center;
justify-content:space-between;(两端对齐)
justify-content:space-around;(四周留白分布对齐)
- 子元素在侧轴的对齐方式
align-items:flex-statr;
align-items:flex-end;
align-items:center;
align-itmes:baseline;(基线对齐)
align-itmes:stretch;(拉伸-默认)
- 设置元素是否换行显示(flew-wrap)
flex-wrap:warp;(默认nowarp)
- 设置元素换行后相对侧轴的对齐方式
align-content:stretch(默认);
align-content:flex-statr;
align-content:flex-end;
align-content:center;
align-content:space-between;
align-content:space-around;
- flex:1;设置元素在父元素中占的比例;
- order:1;元素排序
- 设置元素自身对齐方式
algin-self:flex-end;
algin-self:flex-start;
algin-self:center;
rem适配
浏览器默认文字大小16px;
em:长度单位,相对当前标签文字大小
rem:长度单位,相对于当前根目录标签HTML的文字大小
rem适配的思路就是:
用不同设备宽除以相同数得到不同设备html文字大小,然后用设计图尺寸除以文字大小得到rem倍数,因为不同设备根目录文字大小不同,所以不同文字大小乘以相同倍数得到不同设备的尺寸来适配
媒体查询
什么是媒体查询?
1, 媒体指的就是各种设备(移动设备,PC设备) 2, 查询指的就是要检测属于哪种设备 总结: 媒体查询:通过查询当前属于哪种设备,让网页能够在不同的设备下正常的预览
学习媒体查询的核心是什么?
实现页面在不同设备下正常预览.[判断当前设备]
媒体类型
将不同的设备划分为不同的类型,称为媒体类型
- all (所有的设备)
- print (打印设备)
- screen(电脑屏幕,平板电脑),智能手机
媒体特性
用来描述设备的特点,比如宽度,高度...
- width 网页显示区域完全等于设置的宽度
- height 网页显示区域完全等于设置的高度
- max-width / max-height 网页显示区域小于等于设置的宽度
- min-width / min-width 网页显示区域大于等于设置的宽度
- orientation: portrait (竖屏模式) | landscape (横屏模式)
语法关键字
目的将媒体类型和媒体特性链接到一块,进行设备检测
- and 可以将多个媒体特性链接到一块,相当于且
- not 排除某个媒体特性 相当于非,可以省略
- only 指定某个特定的媒体类型, 可以省略
语法
外联式语法
<link rel="stylesheet" type="text/css" href="01.css" media="only screen and (max-width: 420px)">
内嵌式语法
@media only screen and (max-width: 420px) { body { background-color: red; } } 备注: 多个条件联写 @media only screen and (width: 320px) and (height: 568px) {}
响应式布局
//平板设备
@media only screen and(max-width:980px){
.header {
}
}
//手机设备
@media only screen and(min-width:320px)and (max-width:768px) {
.header {
}
Amaze UI:[amazeui.org]
Framework7:[framework.taobao.org]
Bootstrap:[bootcss.com.]
EasyUI[jeasyui.net]
EXTjs[extjs.org.cn]
织梦cms/动易cms
栅格布局
将网页人为的划分为均等的长度,然后排版布局,通常以百分比为单位
Bootstrap[Bootstrap 是移动设备优先的]
介绍
用来开发响应式布局的 HTML + CSS +JS 的框架
下载
点击链接下载
生产环境版本: 代码已经被压缩过,可以直接放到服务器上部署. 源代码版本: 代码没有经过压缩,用户可以修改源代码
通过link标签可以引用
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
通过npm安装
npm install bootstrap
开始使用
1. 准备工作 <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> <!-- 保证IE浏览器始终以最新版本渲染 --> <meta http-equiv="X-UA-Compatible" content="IE=edge"> 让部分国产浏览器默认采用高速模式渲染页面 <meta name="renderer" content="webkit"> 2. 在HTML页面中引入Bootstrap对应的CSS文件 <link rel="stylesheet" type="text/css" href="css/bootstrap.css"> 3. 例如: <table class="table table-hover"> <tr> <td>123132</td> <td>123132</td> <td>123132</td> <td>123132</td> </tr> </table>
排版
标题
☞ 可以直接使用 <h1></h1> 到 <h6></h6> 标签 ☞ 可以给标签设置 .h1 到 .h6 的类名表示标题
其他行内元素
☞ Bootstrap 支持所有HTML标签行内元素 ☞ 例如: <mark>让文本高亮显示</mark> | <del> 删除线 </del> | <s></s> <strong></strong> | <em> </em> ... ☞ 新标签: <small>小号文本标签</small> 或者 .small类名可以实现相同效果
对齐方式
.text-left : 文本左对齐 .text-center: 文本居中对齐 .text-right: 文本右对齐
改变字母大小写
.text-lowercase: 将字母全部转换为小写 .text-uppercase: 将字目全部转换为大写 .text-capitalize: 将首字母转换为大写
列表
☞ 去掉列表的默认样式: .list-unstyled <ul class="list-unstyled"> <li></li> </ul> ☞ 列表项在一行上显示: .list-inline <ul class="list-inline"> <li></li> <li></li> </ul> ☞ 实现水平的自定义列表: .dl-horizontal <dl class="dl-horizontal"> <dt></dt> <dd></dd> </dl>
-
表格
样式设置
☞ 给table标签添加 table类 <table class="table"> </table> ☞ 各行变色表格效果添加 table-striped类 <table class="table table-striped"> </table> ☞ 设置表格边框添加 table-bordered类 <table class="table table-bordered"> </table> ☞ 设置鼠标悬停时候样式添加 table-hover类 <table class="table table-hover"> </table> ☞ 设置表格设状态: <tr class="active">...</tr> <tr class="success">...</tr> <tr class="warning">...</tr> <tr class="danger">...</tr> <tr class="info">...</tr>
响应表格
<div class="table-responsive"> <table class="table"> ... </table> </div> 备注: 必须将表格放到类名是table-responsive的标签中
-
表单
<div class="form-group"> <label for="exampleInputEmail1">Emai</label> <input type="email" class="form-control" id="exampleInputEmail1" placeholder="Email"> </div> <div class="form-group"> <label for="exampleInputPassword1">密码</label> <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password"> </div> 总结: 1. 给表单控件设置 类名 form-control 可以实现默认样式的设置
提示信息和表单控件一行上显示
☞ 为form标签添加 form-inline类名即可 <form class="form-inline"> <div class="form-group"> <label for="exampleInputName2">Name</label> <input type="text" class="form-control" id="exampleInputName2" placeholder="Jane Doe"> </div> </form> 总结: 1. 让表单中表单控件在一行上显示,给父元素设置form-inline类名 ✔ 必须保证表单控件的类名是form-control 或者 放到一个 form-group的标签中
多选框
<div class="checkbox"> <label> <input type="checkbox" value=""> Option one is this and that—be sure to include why it's great </label> </div>
单选框
<div class="radio"> <label> <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked> Option one is this and that—be sure to include why it's great </label> </div>
一行上显示的多选框
<label class="checkbox-inline"> <input type="checkbox" id="inlineCheckbox1" value="option1"> 1 </label> <label class="checkbox-inline"> <input type="checkbox" id="inlineCheckbox2" value="option2"> 2 </label>
一行上显示的单选框
<label class="radio-inline"> <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1 </label> <label class="radio-inline"> <input type="radio" name="inlineRadioOptions" id="inlineRadio2" value="option2"> 2 </label>
下拉列表
<select class="form-control"> <option>1</option> <option>2</option> <option>3</option> <option>4</option> <option>5</option> </select>
按钮
<button type="button" class="btn btn-default">(默认样式)Default</button> <button type="button" class="btn btn-primary">(首选项)Primary</button> <button type="button" class="btn btn-success">(成功)Success</button> <button type="button" class="btn btn-danger">(危险)Danger</button>
-
栅格布局
栅格系统用于通过一系列的行(row)与列(column)的组合来创建页面布局
使用步骤
1. 必须放到类名是 .container 的容器中 <div class="container"> <div class="row"> <div class="col-md-10">.col-md-10</div> <div class="col-md-2">.col-md-2</div> </div> </div> 2. 设置列数:一共12列 col-xs-number --- 超小屏幕 手机 (<768px) col-sm-number --- 小屏幕 平板 (≥768px) col-md-number --- 中等屏幕 桌面显示器 (≥992px) col-lg-number --- 大屏幕 大桌面显示器 (≥1200px) 例如: <div class="col-xs-3 col-sm-5"></div> 在小屏幕占3列 在平板设备下占5列 3. 设置列偏移 col-md-offset-number | col-sm-offset-number 从左向右偏移 4. 从堆叠到水平排列 ☞ 默认元素独占一行显示 --- 堆叠 ☞ 设置元素占列数,可以在一行上显示 --- 水平排列 5. 流式布局 : 让元素的固定宽度为100%布局 <div class="container-fluid"></div> 6. 列排序 <div class="row"> <div class="col-md-9 col-md-push-3">.col-md-9 .col-md-push-3</div> <div class="col-md-3 col-md-pull-9">.col-md-3 .col-md-pull-9</div> </div>
JavaScript语法
掘金 思否 简书
javascript的组成
- ECMAscript(核心)
描述了语言的基本语法和数据类型 - DOM
文档对象模型,一套操作页面元素的API - BOM
浏览器对象模型,一套操作浏览器功能的API
javascript的书写位置
- 行内式
<input type="button" value="按钮" onclick="alert('Hello World')" />
- 内嵌式
<head>
<script type="text/javascript">
alert('Hello World!');
</script>
</head>
- 外链式
<script src="main.js"></script>
变量
-
什么是变量
- 是计算机内存中存储数据的标示符
-
为什么要使用变量
- 可以方便的获取和修改内存中的数据
-
如何使用变量
- var声明变量
var age;
- 变量赋值
1.var age; age=18; 2.var age=18;
- 同时声明多个变量
var age,zheTihs,sex; age=10; zheTihs='zs';
- 变量的命名规范和规则
- 由字母、数字、下划线、$符号组成,不能以数字或特殊符号开头
- 不能示关键字(在js中具有特殊功能的字)和保留字(预备关键字),例如:for、while
- 区分大小写
- 建议变量名要有意义
- 建议使用驼峰命名法
数据类型
用来描述变量的具体特征(在内存中的存储特征)
数据类型比较
- 引用类型: 比较的是内存地址 so [1,2,3]==[1,2,3] =>false
- 简单类型: 比较的是具体值
简单数据类型
- Number
alert(Number.MAX_VALUE);获取数字类型最大值;
alert(Number.MIN_VALUE);获取数字类型最小值;- 整数
- 浮点数
- var n=5e-324 //5乘以10的-324次方
- 浮点数的最高精度是17位小数,但在进行算术计算时其精确度远远不如整数
- 不要判断来两个浮点数是否相等
- 数值判断
- NaN: not a number
- NaN与任何数都不相等,包括它本身
- isNaN:is not a number(用来判断不是一个数字对不对,不是数字true,是数字false,这里面是不是数字会有一个隐式number()转换。)
- NaN: not a number
- String
-
转义符
- 和实体字符一样,为了避免一些字符的冲突
- '——就是单引号
- "——双引号
- \——斜杠
- \n——就是换行
- \r——回车符
var str="今天学习\'js\'"
-
字符串长度
- length属性用来获取字符串的长度,空格也会被字符串长度计算;
console.log(str.length);
- 字符串拼接
- 两边只要有一个是字符串,那么+就是字符串拼接功能
- 两边如果都是数字,那么就是算术功能
-
- Boolean
- 字面量ture和false
- 计算机内部存储:ture为1,false为0
- Undefined
- 表示一个只声明没有赋值的变量
- 如果变量的值是undefined,那么变量的数据类型就是undefined类型
复杂数据类型
- Object(数组也是对象类型)
- {}
- 函数
- Null(是一个number类型 )
- 表示一个空,变量的值如果想为null,必须手动设置
- NaN不等于NaN,例如:alert(NaN==NaN);输出false。
获取变量的类型
- typeof(变量)
字面量
- 在源代码中一个固定值的表示方法
- 数值字面量:8,9,10
- 字符串字面量:‘黑马程序员’,‘大前端’
- 布尔字面量:true,false
注释
- 单行注释
//这是一个变量 var age=10;
- 多行注释
/* var age=18; console.log(age); */
数据类型转换
谷歌浏览器:字符串黑色/数值类型蓝色/布尔类型蓝色/undefined、null灰色
转换成字符串类型
- toString()
var num = 5;
console.log(num.toString());
- string()
- 这个函数存在的意义,有些值没有toString()这个方法,这个时候可以使用string()方法(它本质上是一个构造函数),例如:undefined和null
- 字符串拼接 +
转换成数值类型
- Number()
- 可以把任意值转换成数值,如果要转换的字符串中有一个不是数值的字符,返回NaN
- 空字符串会转换成0
- 空数组会转换成0;
- boolean,ture转1,false转0;
- null会转换成0;
- undefind会转换成NaN;
- parsenInt()
- 转换成整数,如果第一字符是数字或者运算符会解析遇到非字符返回结束
- 如果第一个字符不是数字就返回NaN
- 严格parsenInt(a,10);后面表示转换成几进制,默认10进制;
- parseFloat()
- 转换成浮点数,和parsenInt()一样
- 会解析第一个. 遇到第二个.或者非数字返回结束
- 如果解析的内容只有整数,解析成整数
- +,-,0等运算
- 隐式类型转换
- — * / % 会转换成数字
- +号有一个是字符串就会转换成字符串拼接
- ++ – 会转换成数字
- < > 如过有一边是数字就转换成数字比较,如果两边都是字符串就是字符串比较,字符串比较的特点是:从第一位开始一位一位的比。
- ! 会转换成boolean类型
- == === 会转换成boolean,===会判断数据类型,==只比较数字是否相等,不会按字符串方式比较
var str = '500';
console.log(+str); // 取正
console.log(-str); // 取负
console.log(str - 0);
转换成布尔类型
- Boolean()
- 0/“空字符串”/null/undefined/NaN 会专换成false
- 其他都转换成true
操作符
算术运算符
- 一元运算符
- 只有一个操作数的运算符
- ++ 自身加1
- 在前或者在后,都是变量自身加1;
- 如果将++n1或着n1++赋值给一个新的变量,这个新的变量是不同的;
- —— 自身减1
- 前置++
- 先自身加在赋值给新的变量
var num1 = 5; var num2; num2=++num1 + ++num1;
这里对应结果是:13=6+7;
- 后置++ - 先赋值给新的变量再自身加
javascript
var num1 = 5;
var num2;
num2=num1++ + num1++;
这里对应结果是:11=5+6;
原理:
var a=3;
b=a++;//b=3,a=4
c=++a;//a=4,c=5;
``````
- 二元运算符
- 两个操作数的运算符:+ - * / %
- 如果除数是0,那么结果是无穷大;
- 三元运算符
- 其实就是if。。else。。的语法简写
- 语法:
//条件?(如果条件成立执行问号后面的代码):(如果条件不成立执行冒号后面的代码);
var a=prompt("");
var b=prompt("");
n1>n2 ? alert("最大值是n1") : alert("最大值是n2")
逻辑运算符(布尔运算符)
- || 或 两个操作数有一个是true,则为true,否则为false
//这里从左往右走,如过第一个条件假,走第二个条件,如果是值依然返回值。
var a=1>9||30;
alert(a);//这里a弹出30;
// 只要有一个条件为true时,结果就为true;
// 当两个条件都为false时,结果才为false;
// 当一个条件为true时,后面的条件不再判断
// 注意:当数值参与逻辑或运算时,结果为true,会返回第一个为真的值;如果结果为false,会返回第二个为假的值;
- && 与 两个操作数同时为true,结果为true,否则为false
//这里从左往右走,如过第一个条件假,返回false,如果第一个条件真,走第二个条件,如果是值可以返回值。
var a=12>9&&30;
alert(a);//这里a弹出30;
// 两边条件都为true时,结果才为true;
// 如果有一个为false,结果就为false;
// 当第一个条件为false时,就不再判断后面的条件
// 注意:当数值参与逻辑与运算时,结果为true,那么会返回的会是第二个为真的值;如果结果为false,返回的会是第一个为假的值。
- ! 非 取反
当条件为false时,结果为true;反之亦然。
比较运算符
- < >
- (>=)
- <=
- == !=(这两个都是不判断类型) === !==(这两个判断类型)
赋值运算符
- += :n1=n1+3(n1+=3;)
- -=:n1=n1-3(n1-=3;)
运算符的优先级
if条件判断
if(条件){
逻辑代码(条件true执行)
}
else{
逻辑代码(条件false执行)
}
//多条件判断
if(条件){
}else if (条件) {
}else if (条件) {
}else{
}
switch语句
如果能够明确变量的具体值,可以考虑用switch语句
语法:
switch (变量) {
case 变量值1://这里注意变量值和变量的类型要一样,不然会执行default
逻辑代码;
break;//加break就是条件满足停止继续执行
case 变量值2:
break;
default:
逻辑代码;
break;
}
循环
while循环
- 语法:
while(条件){
循环体(逻辑代码)
} - 执行过程:
1.先判断条件是否成立
2.如果条件为true,那么程序进入循环体执行代码
3.执行完循环,继续判断条件是否成立,如果成立就继续执行
4.如果条件是false,代码不再执行
//1到100求和
var i=1;
var sum=0;
while (i<=100){
sum+=i;
i++;
}
alert(sum);
do…while循环
- 语法:
do{
循环体代码(变量自增自减)
}while(条件)
- 执行
1.先执行do中循环体代码;//和while的区别
2.判断条件是否成立;
3.如果成立继续执行;
4.执行完循环,继续判断条件是否成立,如果成立就继续执行
5.如果条件是false,那么循环代码结束
for循环
- 语法:
for(变量初始化;条件;变量自增(自减)){
循环体代码
} - 执行过程:
1.先变量初始化
2.判断条件
3.条件true,执行循环体代码
4.变量自增
5.判断条件
6.条件true,执行循环体代码
7.变量自增
continue语句
在程序中如果执行到continue语句时,程序会跳过本次循环进入到下一次循环中
//输出1-10,遇到5跳过
for(var i=1;i<=10;i++){
if(i==5){
contonue;//遇到i等于5不往下走了,直接返回循环i++;
}
console.log(i);
}
break语句
当程序执行到break语句的时候,会结束循环程序
for(var i=1;i<=10;i++){
if(i==5){
break;//遇到i==5,不循环了,直接结束整个循环程序;
}
console.log(i);
}
数组
数组和变量都是在程序中保存数据的容器,数组一次可以存放多条数据。
- 通过构造函数创建数组
var arry=new arry(5);//这里面5是数组的长度 ,里面每一个值是undefined。
var arry=new arry(10,20,30,40);//这里面是数组中存的数据,数组的长度是4.
- 通过字面量的方式创建数组
var arry=[];
//直接给数组赋值
var ary=[1,2,"asd",ture];
//获取数组中的值
console.log(ary[1]); //打印出2
//通过循环获取数组中的买一个值(遍历)
for(var i=0;i<4;i++){
console.log(ary[i]);
}
//获取数组的长度
ary.length;
//通过索引的方式给数组赋值
//在数组中索引是从0开始的
var ary=[];
ary[0]=1;//把数字1放到索引是0的数组中
//删除数组的方法:
arry.splice(要删除的位置,要删除的长度);
//判断数组中是否存在某一项
arry.indexof(要判断项);
伪数组
和数组一样都有索引和长度,伪数组不能调用真正数组中内置的方法
函数
将页面中的一段功能代码封装到一个容器中方便重复使用
1.声明函数
//关键字声明
function f1(){
}
//表达式申明
var f1=function(){
}
2.调用函数
3.函数中的参数
函数的参数可以是任何的数据类型
形参:定义变量或者数组
实参:具体值
//有参函数
function fn (a,b){
}
//调用函数时候,传递参数(实参)
fn(100,1000);
- 返回值:返回变量的值
任何的数据类型都可以是返回值
return max;
a. 函数外部不能使用函数内部的变量
b.函数内部可以使用函数外部的变量
c.一个函数中只能有一个返回值,如果要返回多个值,可以用数组
d.程序中,一旦执行到return,就返回值,return后面的程序不再执行
e.一个函数如果没有return,函数默认返回值是undefined;
function (arry){
var max=arry[0];
for(var i=0;i<arry.length;i++){
if(max<arry[i]){
max=arry[i];
}
}
return max;//把max的值返回到函数外部
//如果不用返回值,就需要在函数内部弹出结果
alert(max);
}
var abc=[1000,2,3,100];
var n1=get_max(abc);//定义一个变量接受返回的值
alert(n1);
匿名函数和自调用函数
- 命名函数
function fn(){
}
- 匿名函数
function(){
}
- 自调用函数
自调用匿名函数最大的作用就是:封装作用域(防止污染全局变量);
(function fn(a){
alert(a);
})()//这个小括号里面的实参可以传给a
- 函数执行方式三种
1.通过函数名调用(命名函数)
2.通过阐述自己调用自己(自调用函数)
3.把函数赋值给一个变量,通过变量调用(匿名函数) - arguments
arguments是【一个用来存放函数中所有参数】的集合,也叫伪数组
当函数的行参个数不确定时,使用arguments - 作用域
-
全局作用域
-
局部作用域
在函数内部形成的一块区域 -
块级作用域
-
- 变量
- 局部变量
在 JavaScript 函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它。(该变量的作用域是局部的)。
您可以在不同的函数中使用名称相同的局部变量,因为只有声明过该变量的函数才能识别出该变量。
只要函数运行完毕,本地变量就会被删除。 - 全局变量
在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它 - 向未声明的 JavaScript 变量来分配值
如果您把值赋给尚未声明的变量,该变量将被自动作为全局变量声明。(即使他在函数内部执行)
- 局部变量
- 预解析
当代码在执行之前,代码会执行一次解析操作- 变量提升
当代码执行之前,会将变量的定义提升到当前作用域的开始位置(不包含变量的赋值) - 函数提升
当代码执行之前,会讲函数的声明提升到当前作用域的开始位置(不包含函数的调用) - 变量声明及函数声明预解析时,变量解析为undefined,函数解析为其本身。预解析时函数声明优先级高于变量声明,函数声明会覆盖变量声明,但不会覆盖变量赋值。如果声明变量的同时初始化或赋值那么变量优先级高于函数。
- JavaScript的变量及函数声明提升及预解析 - 孔zheng - 博客园
- 变量提升
var a=25
abc();
function abc(){
alert();
var a=10;
}
//预解析>>变量提升+函数声明提升
var a;
function abc(){
var a;
alert (n1);
a=10;
}
a=25;
abc();
对象
JavaScript 中的所有事物都是对象:字符串、数字、数组、日期,等等。
- 对象分为值类型(简单类型)【栈存储】和引用类型(复杂类型)【堆存储】
在 JavaScript 中,对象是数据(变量)拥有属性和方法的数据。
属性:与对象相关的值(特征)。
方法:能够在对象上执行的动作(本质就是函数)。 - 创建对象(通过字面量的方式)
//对象中的值都是以键值对形式出现的
//key:值;
//例如创建一个汽车对象
var car={
name:‘法拉利’,
color:red,
qidong:function(){
alert("汽车启动");
},
shace:function(){
alert("汽车停止");
}
}
- 构造函数和函数的区别
- 如果我们希望通过function实现一个功能(函数)【首字母小写】
- 如果我们希望通过function创建一个对象(构造函数)【首字母大写】
- 创建对象(通过构造函数创建)
//通过js中内置的构造函数创建对象
var zs=new object();//内置
zs.name="zs";
zs.age=18;
关键字new:实现调用构造函数,创建对象
//工厂方式
function createPeole(uname,uage,uheight){
var obj=new Object();//内置
obj.name=uname;
obj.age=uage;
obj.height=uheight;
return obj;
}
var zs=createPeole("zs",18,180);
var ls=createPeole("ls",18,180);
alert(typeof zs);>>object
//自定义构造函数创建对象
function People(uname,uage,uheight){
this.name=uname;//this指向自定义构造函数创建的对象
this.age=uage;
this.height=uheight;
return this;
}
var zs=new People("zs",18,180);//自定义构造函数创建的对象
var ls=new People("ls",18,200);
- 获取对象中的值
//可以直接通过 对象.属性名()获取
alert(car.name);
//可以通过 对象["属性名"];
alert(car["name"]);
- 修改对象中属性的值
car.name="布卡龙";
- 删除对象中的值
delete car.name;
- 增加一个值
car.name="霸道";
- 对象遍历
for(key in car){
console.log(car[key]);
//不能用下面这两个,因为key是一个存储了对象中所有属性名的变量
//console.log(car.key);
//console.log(car['key']);
}
内置对象【String、Math、Array】
- alert(‘在网页中以弹窗形式显示信息’);
var username;
username=‘张三’
username=‘莉丝’ //一个变量中只能保存一个值,最后一次赋值结果;
alert(username);//要输出变量中的值,不用加引号; - console.log(‘在浏览器控制台中输出消息’);
- document.write(‘在body标签中输出消息,还可以在网页中输出html标签’);
- document.write("< h1 style=‘color:red’>标题");
- prompt(“网页中接收用户输入的消息(这里面是提示信息)”)[用户输入的内容是字符串];
- confirm(“在网页中可以体现确定和取消的提示窗口”);//返回布尔值
Date
- //获取当前系统时间
var d=new Date();//=new Date(‘1992-8-8’)获取指定日期的时间//=new Date(year,month,day);
console.log(d);
//获取当前系统时间对应的毫秒表示法
console.log(d.valueOf());
console.log(d.getTime());//从1970年1月1日到今日的毫秒数 - var d=new Date();
- d.toString();//转换成字符串类型显示
- d.toLocaleDateString();//返回 本地的日期格式
- d.toLocaleTimeString();//返回 本地的时间格式
- d.getFullYear();//返回年
- d.getMonth();//返回月,月从0开始
- d.getDay();//返回周几,周日是0
- d.getDate();//返回每月中的第几天
- d.getHours();//获取小时
- d.getSeconds();//获取秒
- d.getMinutes();//获取分
Arry
- ary.reverse();//反转数组
- ary.join("|");//将数组以一个字符链接到一块,返回的是一个字符串
- ary.sort(function(){})//排序
- 栈方法(先进后出)
ary.push();//向数组arry[arry.length]添加值
ary.pop();//删除数组arry最后一个值 - 队列方法(先进先出)
ary.shift();//删掉数组中的第一个值
ary.unshift();//添加数组中第一个的值 - 数组合并:将数组合并后,返回一个新数组
var ary=[1,2,3,4];
var ary1=[‘a’,‘b’,‘c’];
ary.concat(ary1); - ary.slice(begin,end)
**begin** (可选)
从该索引处开始提取原数组中的元素(从0开始)。
如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2)表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。
如果省略 begin,则 slice 从索引 0 开始。
**end**(可选)
在该索引处结束提取原数组元素(从0开始)。slice会提取原数组中索引从 begin 到 end 的所有元素(包含begin,但不包含end)。
slice(1,4) 提取原数组中的第二个元素开始直到第四个元素的所有元素 (索引为 1, 2, 3的元素)。
如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。 slice(-2,-1)表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。
如果 end 被省略,则slice 会一直提取到原数组末尾。
如果 end 大于数组长度,slice 也会一直提取到原数组末尾。
//截取数组,第一个表示从哪开始,第二个表示从哪结束,end值取不到
var ary1=[‘a’,‘b’,‘c’,‘d’,‘e’,‘f’,‘g’];
ary1.slice(2,5);
- 一个参数表示截取数组,和slice()一样
两个参数,第一个带标从哪开始,第二个代表截取的个数(从截取位置数)
三个参数,第三个代表替换
ary1.splice(2,4,‘捷克’);//————ary1=[‘a’,‘b’,‘捷克’,‘g’]; - 获取数组中对应的索引
ary.indexOf();//找数组中的某个值,找到返回索引,找不到返回-1
ary.lastIndexof(); - 循环数组
ary.find();
ary.forEach(function(item,index,a){})//item是数组项的值,index数组索引,这个方法没有返回值,a表示整个数组
ary.filter(function(item,index){})//有返回值
str
- str.charAt();//通过索引获取指定位置处的内容
- str.concat();//字符串拼接,相当于+
- //截取一个新的字符串,从第二个截取3个,end值取不到
- str.slice(2,3);
str=‘abcdef’;
str.slice(2,3);//----str=‘c’; - str.substring(index,index2);//index表示截取位置,index2表示索引数组截取到第几个
- str.substr(index,2);//index表示截取位置,2表示从这个位置开始的截取长度
- str.trim();//删除空格
- str.replace(a,b);//用b替换a
- //将字符串以一个字符分割,返回分割后的数组
str=‘ab=cd=ef’;
str.split(’=’);//----ary=[‘ab’,‘cd’,‘ef’] - str.toLocaleUpperCase()//转换成大写
- str.toLocaleLowerCase()//转换成小写
- eval(‘js代码’)//eval会解析字符串中的js代码
Math
提供了一系列的与数学相关的属性或方法
- Math.PI 获取圆周率
- Math.pow(x.y); 求x的y次幂
- Math.round(x); 对x值进行四舍五入运算,返回一个整数
- Math.abs(x); 对x值进行取绝对值
- 求三角函数:x的单位是弧度制
Math.sin(x);
Math.cos(x);
Math.tan(x);
- Math.max(1,2,3,4); 获取一组数字的最大值
- Math.ceil(x); 天花板函数 (遇小数进1制)
- Math.floor(x); 地板函数 (遇小数舍掉)
- Math.random(); 随机数 (随机产出一个大于等于0且小于1的伪随机数)
静态成员
直接通过对象.属性(方法);
var get={
test:function(){
}
}
get.test();
实例成员
通过构造函数创建对象,然后通过对象.属性(方法);
function Get(){
this.test=function(){
}
}
var n1=new Get();
Get.test();
//获取当前系统时间
var d=new Date();//=new Date('1992-8-8')获取指定日期的时间//=new Date(year,month,date);
console.log(d);
//获取当前系统时间对应的毫秒表示法
console.log(d.valueOf());
console.log(d.getTime());
//H5中的方法
Date.now();
webAPI
浏览器平台对外公开的操作浏览器和网页的接口
DOM
文档树:浏览器在加载html文件时,会把文档、文档中的标签、属性、文本、注释转换成对象,然后按照标签的关系以树状结构存储到内存中
节点对象:文档树中的对象也称为节点对象,包括(文档、元素、文本、属性、注释)
获取元素
- 获取body通过documen.body
- 通过getElementById() id名来获取单个元素
- 通过getElementsByTagName() 标签来获取一组元素,返回的是一个伪数组,不能给组注册事件,通过索引给每一个加事件
- 通过querySelector() 通过选择器来获取单个元素(如果有多个相同标签,选择的是第一个)
- 通过querySelectorAll()通过选择器来获取一组元素
给元素注册事件
- 事件:用户和网页的交互行为
- 事件类型
onclick 鼠标点击事件
onmouseenter 鼠标进入元素事件
onmouseleave 鼠标离开元素事件
- 事件三要素:事件源、事件类型、事件处理程序
//语法:事件源.事件类型=事件处理程序
btn.onclick=function(){
console.log(this);
};
//事件处理程序的本质
onclick本质上就是事件源这个对象中的一个键值,默认值是null
给事件源注册事件,本质上就是会给onclick赋值一个函数,所以onclick是事件源的一个方法
当用户点击时,浏览器自动调用了btn.onclick()
事件处理程序中的this关键字指向事件源本身
//取消a标签的默认跳转行为
方式1
事件处理程序最后:return false;
方式2
给a标签的href设置javascript:,表示将来点击a,会阻止默认跳转行为,并仅仅会执行js代码
方式3
e.prevenDefault(); 有兼容性问题
//通过a可以打开拨号应用
<a href="tel:">拨号</a>
//通过a可以打开默认邮件应用
<a href="mailto:">邮件</a>
操作元素的属性
- 常见属性:id、title、href、src、innerText、textContent、innerHTML
语法:
获取属性值 元素.属性名
设置属性值 元素.属性名="";
//获取类名,不能用元素.clss,要用元素.className
innerText/textContent,获取文本
//textContent有兼容性问题
innerHTML,获取内容,包含子标签和文本
- 通过style操作元素属性
var div=getElementById('dear');
div.style.backgroundColor="red";
- 通过className操作元素属性
var div=getElementById('dear');
div.className='a';
//这里面a是div的class类名,样式写在css里面了
- 操作表单元素的属性
//value操作表单元素的内容
元素.value;返回字符串
//checked操作表单元素是否选中
元素.checked;返回布尔值
//disabled操作表单元素是否禁用
元素.disabled;返回布尔值
//selected操作表单下拉框
元素.selected;返回布尔值
option.selected=false;
//下拉框的多选效果用multiple
<select id="sel" multiple></select>
//在原生js中没有:selected选择器
:checked选择器针对所有表单元素
- 自定义属性操作
//获取自定义属性
元素.getAttribute('属性名');
//修改自定义属性
元素.setAttribute('属性名,要修改的')
//移除自定义属性
元素.removeAttribute('属性名')
//注意:这三个方法还可以操作系统自带的属性
- 节点的层级
//通过子节点获取父节点:
子节点.parentNode
//通过父节点找子节点:
父节点.childNodes(这里获取的子节点,包含text和元素)
父节点.children;(这里获取的是子元素)
父节点.firstElementChild;(获取第一个子元素)
父节点.lastElementChild;(获取最后一个子元素)
//获取兄弟节点
节点.nextElementsibling;(获取下一个兄弟)
节点.previousElementsibling;(获取上一个兄弟)
- 节点的属性
nodeType//1-——元素/3———text
nodeName//大写的标签名——元素/#text——text
nodeValue//null————元素/文本内容——文本
动态操作元素(创建、追加、删除、克隆)
- 动态创建元素
//通过innerHtml动态创建
var str=ul.innerHTML;
ul.innerHTML=str+'<li>我是新来的</li>'
//通过createElement()创建(性能高)
var newLi=document.createElement('li');
ul.appendChild(newLi);
newLi.innerText="我是新来的"
- 动态追加元素(移动元素)
//通过appendChild()追加元素
appendChild()
- 动态删除元素
//通过removeChild()删除元素
removeChild()
- 动态插入元素
//通过inserBefore()删除元素
父级元素.inserBefore(新节点,旧节点)
- 动态替换元素
//通过replaceChild()删除元素
父级元素.replaceChild(新节点,旧节点)
- 动态克隆元素
//通过cloneNode()删除元素
元素.cloneNode(布尔值);false——只克隆元素本身/true——克隆元素和内部所有元素
事件
用事件监听注册事件(标准方式)
因为以前注册事件的方法不能给同一个按钮注册多次相同事件
- 语法:
事件源.addEventListener(‘事件’,事件处理程序,是否捕获);
是否捕获:布尔值,捕获——true/冒泡——false(默认) - 解绑事件(前提:注册事件处理程序时,处理程序要有名字)
语法:
事件源.romoveEventListener(‘事件’,事件名);
btn.addEventListener("click",function(){
console.log(1);
})
事件流
- 事件触发后的三个阶段(捕获阶段、目标阶段、冒泡阶段)
- 注意:事件触发后,这三个阶段始终存在:捕获——目标——冒泡,但是触发后,针对捕获和冒泡只能启用一个
- 冒泡:最特定的事件目标到最不特定的事件目标
- 捕获:从DOM树最上层开始触发一直到捕获到事件源
- 停止事件冒泡
e.stopPropagation();
事件对象
- 什么是事件对象
在事件触发后,事件处理程序中,所获取并操作的对象document.onclick=function(e){ //处理程序中第一个行参就是事件对象 console.log(e); }
- 获取事件对象
- 事件对象的公共属性target:指向最先触发的那个元素(因为事件冒泡)
- 事件处理程序的第一个形参
- ie低版本有兼容问题用window.event
- 鼠标事件对象
- 鼠标事件类型
- 鼠标事件对象相关属性
事件对象.clientX/.clientY【参照浏览器】
事件对象.pageX/.pageY【参照文档】
事件对象.offsetX/.offsetY【参照元素】
- 键盘事件对象
- 键盘事件类型
- 键盘事件对象相关属性
事件对象.keyCode【获取对应键码(number)】
事件对象.altKey【表示alt键是否按下,返回布尔值,true按下】
事件对象.ctrlKey【表示ctrl键是否按下,返回布尔值,true按下】
事件对象.shiftKey【表示shift键是否按下,返回布尔值,true按下】
- touch事件对象
- 手指事件类型
- touch事件对象相关属性
事件对象.touches 【位于屏幕上所有手指列表】
事件对象.targetTouches 【位于元素上的手指列表】
事件对象.changedTouches【手指改变时的手指列表】(手指松开事件用这个属性)//这个会获取两个点,手指和屏幕刚接触和手指和屏幕刚离开 - 获取手指位置
手指对象的clientX/Y 【参照可视区域的水平/垂直像素距离】e.touches[0].clientY
手指对象的pageX/Y 【参照文档的水平/垂直像素距离】
事件委托
- 什么是事件委托
把子孙元素的事件注册,完全交给上级元素代理
作用:减少内存浪费并且上级元素可以代理未来新动态添加的元素 - 如何实现事件委托
- 给子孙上级注册事件
- 事件对象中通过事件对象.target获取最先触发的元素(因为事件冒泡)
- 通过事件对象.target的nodeName检测最先触发的是否是指定元素
事件类型
@普通事件注册方式:非官宣,兼容好,但是同一个事件源多次注册相同事件会覆盖
@普通事件解绑方式:btn.οnclick=null;
@用事件监听注册事件(标准方式),有兼容性
事件源.addEventListener(‘事件’,事件处理程序,是否捕获);
@解绑事件(前提:注册事件处理程序时,处理程序要有名字)
事件源.romoveEventListener(‘事件’,事件名);
-
输入框事件
oninput 【输入框输入事件】
textarea.οninput=function(){}; -
鼠标事件
onclick 【鼠标点击事件】
onmouseenter 【鼠标进入事件】//不支持冒泡
onmouseleave 【鼠标离开事件】//不支持冒泡
onmouseover 【鼠标进入事件】
onmouseout 【鼠标离开事件】
onmousedown 【鼠标按下事件】
onmouseup 【鼠标弹起事件】
onmousemove 【鼠标移动事件】 -
键盘事件(一般都给document绑定)
onkeydown 【键盘按下事件】
onkeyup 【键盘弹起事件】 -
滚动事件
onscroll 【滚动条事件】 -
手指触摸事件(用事件监听注册)
document.addEventListener('touchend',function(){ console.log("松开"); })
touchstart 【手指按下事件】
touchmove 【手指移动事件】
touchend 【手指松开事件】 -
transitionend事件 【css过渡结束后检测的行为】(事件监听注册)
过渡谁,谁就是事件源
BOM
浏览器对象模型
window对象介绍
-
window.pageYOffset //设置或返回当前页面相对于窗口显示区左上角的 Y 位置。
-
window.pageXOffset //设置或返回当前页面相对于窗口显示区左上角的 X 位置。
这两个相当于document.documentElemnt.scrollTop/ScrollLeft;卷进去的距离 -
window.innerWidth //返回窗口的文档显示区的宽度。
-
window.innerHeight //返回窗口的文档显示区的高度。
- window对象被 称为顶级对象 或全局对象 。
- 因为全局变量和全局函数本质上都是window对象的属性或方法。
- window对象可以省略。
定时器
- 定时器window.setTimeout(callback,time);
- window可以省略
- 只执行一次
- time 延时多久执行,是毫秒(当定时器函数体内的代码和非定时器的代码同时存在时,优先执行非定时器代码,哪怕定时器延时时间是0;)
- callback 函数定义,要执行的程序
- window.clearTimeout(定时器存的变量);清除定时器
- 定时器setInterval(callback,time);
- window可以省略
- 重复执行
- callback 函数定义,要执行的程序
- time 延时多久重复执行,是毫秒(当定时器函数体内的代码和非定时器的代码同时存在时,优先执行非定时器代码,哪怕定时器延时时间是0;)
- window.clearInterval(定时器存的变量);清除定时器
location对象
- location对象,将来操作浏览器的地址栏。
- 属性:
- location.href 设置或获取地址栏地址
- 方法:
- location.reload(); 刷新页面
history对象
- history对象 ,用来操作历史记录
- 属性:
history.length; 获取历史记录的长度 - 方法:
history.back(); 回退上一个历史记录
history.forward(); 前进下一个历史记录
history.go(数字); 正数,表示前进; 负数,表示回退;
navigator对象
- navigator对象, 用来获取浏览器的信息。
- 属性:
navigator.userAgent; 用来获取浏览器的信息
onload事件
- 页面加载事件,一般绑定给window
//不推介使用
window.οnlοad=function(){
//这里当页面中所有资源(DOM树、图片资源、媒体资源、其他外联)加载完,才会执行事件处理程序
}
元素的offset系列属性
- 获取元素大小
元素.offsetWidth/offsetHeight;
返回的是数字,包含【内容+border+padding】; - 获取元素的位置
元素.offsetLeft/offsetTop;//只读属性不能设置(用style.left设置)
获取的位置参照谁看定位关系 - 获取父元素
元素.offsetParent;(是根据定位关系)/元素.parentNode; (根据标签关系获取)
元素的client系列属性
- 获取元素大小
元素.clientWidth/clientHeight;//只读
返回的是数字,包含【内容+padding】; - 获取边框厚度
元素.clientLeft/clientTop;//只读属性不能设置
获取的位置参照谁看定位关系 - 获取父元素
元素.offsetParent;(是根据定位关系) //只读
元素.parentNode;(根据标签关系获取)
元素的scroll系列属性
- 获取元素的大小
元素.scrollWidth/元素.scrollHeight //只读
返回元素的整个宽度(包括带滚动条的隐蔽的地方)
返回的是数字类型,包含【内容+padding+溢出】 - 获取被卷起的页面距离
scrollTop //返回当前视图中的实际元素的顶部边缘和顶部边缘之间的距离
元素.scrollLeft / 元素.scrollTop //该属性不仅可以获取还能设置
特殊情况:当滚动条在窗口上时,onscroll事件注册给window
javacript高级
面向对象和面向过程
面相对象不是替代面向过程,而是面向过程的更高一级的封装
- 面向过程
关注的是过程中的每一个细节 - 面向对象
关注的是让对象做事情
面向对象编程
Object Oriented Programming,简称OOP,是一个编程开发思想。
它将真实世界的各种复杂关系抽象成一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟
面向对象的特征
- 封装:对象把实现过程封装在方法中,调用者只需要调用即可,不用了解实现过程
- 继承:子承父业。对象b可以继承对象a的属性和方法,减少代码冗余
- 多态:一种事物,可以具有多种表现形式
构造函数和实例
- 类(抽象的)
- ES3.0和5.0没有类的概念
创建对象:new 构造函数名(); 构造函数: 内置构造函数:Object、Date、Array、Math 自定义的:Dog、Cat、Shab
- ES6.0有类概念
创建对象:new 类名();
- 实例(对象)
通过构造函数创建的对象 - 类和实例的关系:类是实例的模版,实例是类的一个具体表现
- 构造函数和普通函数的区别
- 命名区别
构造函数:帕斯卡(首字母大写)
普通函数:驼峰(每一个单词首字母大写) - 调用方式:
构造函数:new 构造函数();
普通函数:函数();
- 命名区别
原型
- 获取原型
构造函数名.prototype; - 原型中的constructor属性关联的是对应的构造函数
对象.constructor.name //对应构造函数的名字 - 实例对象和原型的关系
对象查找属性的一个流程
1. 会先从对象本身找
2. 没有,通过_proto_提供的原型地址,找到原型
3. 在原型中找对应的属性和方法
4. 没有,通过原型的_proto_提供的原型地址,找到原型
- 判断对象自身是否具有某个属性(不包含从原型上继承的)
对象.hasOwnProperty(‘属性名’);//ture——有 false——没有 - 原型链
继承
继承时类(子类)与类(父类)之间的关系
原型继承
属性不能改,方法可以改
//人类
function Person() {
name:"人类",
age:10
}
Person.prototype.eat=function() {
}
var p1=new Person();
//学生类
function Student() {}
var stu1=new Student();
//更改子类原型的指向
Student.prototype=new Person();
//给新的原型加一个能找到student函数的contructor属性
Student.prototype.contructor=Student;
借用继承
属性能继承,方法不能
- call方法改变this的指向
语法:函数名.call(调用者,实参,实参);
作用:函数借用时会立即执行,this指向调用者
function Person(name,age) {
this.name=name;
this.age=age;
}
var obj={};
Person.call(obj,'张三',18);
consloe.log(obj); //name:"张三",age:18
组合继承
// 【人类→父类】 function Person(name,age,gender) { this.name = name; this.age = age; this.gender = gender; }; Person.prototype.eat = function() { console.log('我会吃....'); }; Person.prototype.run = function() { console.log('我会跑....'); }; Person.prototype.sayHi = function() { console.log('你好.'); }; // 【学生类→子类】 function Student(name,age,gender) { // this在此的指向是当前创建的学对象 stu1、stu2 var obj = this; // 借用继承 Person.call(obj,name,age,gender); } // 原型继承 Student.prototype = new Person(); Student.prototype.constructor = Student; // 创建一个学生对象 var stu1 = new Student('张三',11,'男'); var stu2 = new Student('李四',12,'女'); stu1.sayHi(); stu2.eat(); // 总结:组合继承 // 借用:借用属性 // 原型:继承的方法
改变函数内部this指向的三种方法
call方法
语法:函数名.call(调用者,实参,实参);
作用:函数借用时会立即执行,this指向调用者
apply方法
语法:函数名.apply(调用者,实参,实参);所有实参要放到数组
fn.apply(obj,[‘zs’,10])
作用:函数借用时会立即执行,this指向调用者
bind方法
语法:函数名.bind(调用者,实参,实参);
作用:函数借用时,不会立即执行,返回一个新的函数,将来手动调用新的函数,this指向调用者
var obj={
0:11,
1:22,
2:33,
3:44,
length:4
};
Array.prototype.push.call(obj,55);
Array.prototype.push.apply(obj,[55]);
Array.prototype.push.bind(obj,55)();
函数的其他成员
函数名.arguments
获取用户传入的实参
函数名.length
获取函数形参个数
函数名.name
获取函数名字
函数进阶
闭包
闭包是能够读取其他函数内部变量的函数
好处:维护私有变量的安全
内存中,谁清理内存中没用的数据——CG(保洁Garbage Collection)
全局作用域
变量的生命周期:当程序关闭时,会被从内存中释放,变成垃圾数据
局部作用域
变量的生命周期:函数执行完就被释放了,变成垃圾数据
作用域链
内层作用域可以访问外层作用域中的变量,但是外层作用域无法访问内层中的变量
判断是否有闭包
- 子函数可以操作外层函数中的局部变量
- 全局作用域中可以操作子函数
function bieshu(){
var a='三儿';
var guanjia=function(v){
console.log(a);
a=v;
console.log(a);
}
return guanjia;
}
var cyqz=bieshu();
cyqz();
递归
什么是递归
程序调用自身的编程技巧称为递归
递归的三个阶段
递归前进段
边界条件
递归返回段
递归的作用
减少代码量
//一组年龄10,12,14,16,18,20...求第n个人的年龄
function age(n){
if(n==1){
return 10;
}else {
return age(n-1)+2; //age(5) <=age(4) <=age(3) <=age(2) <=age(1)=10
}
}
var r=age(5);
console.log(r);//=>18
浅拷贝
两种方法
1)for in 循环
2)Object.assign()
深拷贝
- lodash库:_.cloneDeep()
- jQuery库:$extend(true,obj1,obj2)
- js原生:递归和数据类型判断
正则表达式
是对字符串操作的一种逻辑公式,根据字符串规则实现对字符串的提取、修改、替换
正则表达式的语法
正则表达式的组成
-
普通字符
-
特殊字符(元字符、限定符、中括号、或模式、分组模式、修饰符、正则转译符)
| 字符 | 描述 |
| ---- | :------------: |
|||
|||
|||
|||元字符
\d //匹配数字 \D //匹配非数字 \w //匹配字母数字或下划线
限定符
\d\d //表示查找双数,单数不匹配 \d{11} //查找连续的11个数字 \d{3,} //查找至少3个数相连的数字 \d{4,5} //查找至少3个最多5个数相连的数字,如果是10个数,会分成两组来找
中括号
[] //表示一个范围
或模式
baidu|guge //这两个都可以选中
分组模式
(你好) //表示分组
修饰符
g //表示全局 i //忽略大小写
转译符
\
js中使用正则表达式
- 正则表达式对象
正则对象.test(字符串);用于检测字符串是否匹配规则,返回布尔值
var str="1";
//创建正则对象
var reg=new RedExp('\\d');
//简写方式
var reg=/\d/;
//检查字符串是否匹配
var isOk=reg.test(str);
console.log(isOk);
- 字符串正则方法使用
提取
str.match(正则对象);//返回一个伪数组
替换
str.replace(正则对象);
JQuery
引用
<script src=jquery.js></script>
console.log($===jquery); //ture
//$ 是一个函数
//$("选择器") 函数需要调用
//调用完毕后,返回要给JQuery类型的对象
//创建一个对应的jquery对象
<button id="nbtn"></button>
var $btn=$("#btn");
$.fn=$.prototype; // 它两指向同一个地址,$也可以用jquery代替
##JQuery对象和DOM对象
JQuery对象
//获取对应jquery对象
var $btn=$("#btn");
var #lis=$("li")
//不管是获取一个还是获取一组元素,将来都返回一个伪数组,这个伪数组是jquery对象
DOM对象和JQuery对象的区别
各有各的属性和方法
DOM对象和JQuery对象的转换
- DOM对象转JQuery对象
var btn=document.qureySelector("button");
var $btn=$(btn);
- JQuery对象转DOM对象
var $btn=$("button");
var btn=$btn[0];
//也可以这样
var btn=$btn.get[0];
JQuery注册事件
$(“选择器”).事件名(事件处理程序);
var $btn=$("button");
$btn.click(function(){
alert("1");
})
隐式迭代
//在给一组div注册事件时,jquery库内部自动循环给每一个div注册事件
$("div").click(function(){
//this不是指jquery对象,是指向原生jsDOM对象
//this.text("hello");这个不对
$(this).text("hello");
var num=$(this).index();
$(this).text("hello"+num);
})
JQuery操作样式
- 设置
jquery对象.css(name,value);
$("div").css("width",300);
$("div").css("background","red");
$("div").css({
width:300,
height:300,
background:"blue"
});
- 获取
var w=$("div").css("width");
通过选择器获取JQuery对象
基本选择器
层级选择器
伪类选择器
//:eq(index) ,第几个,索引从0开始的
//:even 选择索引号为偶数的元素,从零开始
//:odd 选择索引号为奇数的元素
$("tody tr:even").css("background","skyblue");
选择器筛选方法(jquery遍历)
选择器eq和筛选方法eq的区别
//选择器 eq
$("li:eq(1)").css("background","red");
//筛选方法 eq
$("li").eq(1).css("background","red");
juqery遍历
// 遍历祖先
对象.parent();// 方法返回被选元素的直接父元素,只会向上一级对 DOM 树进行遍历。
对象.parents(); //方法返回被选元素的所有祖先元素,它一路向上直到文档的根元素 (<html>)
对象.parents("ul"); //使用可选参数来过滤对祖先元素的搜索(只搜索祖先元素是ul的元素)
对象.parentsUntil(); //方法返回介于两个给定元素之间的所有祖先元素
// 遍历后代
children() //方法返回被选元素的所有直接子元素,该方法只会向下一级对 DOM 树进行遍历。
find("*") //方法返回被选元素的后代元素,一路向下直到最后一个后代。[必须传参,*或者指定元素]
// 遍历同胞
siblings() //方法返回被选元素的所有同胞元素。
next() //方法返回被选元素的下一个同胞元素,该方法只返回一个元素。
nextAll() //方法返回被选元素的所有跟随的同胞元素。
nextUntil() //方法返回介于两个给定参数之间的所有跟随的同胞元素
prev(), prevAll() 以及 prevUntil() //方法的工作方式与上面的方法类似,只不过方向相反而已:它们返回的是前面的同胞元素(在 DOM 树中沿着同胞之前元素遍历,而不是之后元素遍历)
// 过滤元素
first() //方法返回被选元素的首个元素
last() //方法返回被选元素的最后一个元素。
eq() //方法返回被选元素中带有指定索引号的元素。索引号从 0 开始
filter() //方法允许您规定一个标准。不匹配这个标准的元素会被从集合中删除,匹配的元素会被返回。
not() //方法返回不匹配标准的所有元素。
方法
对象.show();显示哪个元素
对象.hide();隐藏哪个元素
对象.hasClass();检查是否有类名
对象.addClass();添加类名
对象.removeClass();移除类名,如果不传参,会移除所有类名
对象.toggleClass();如果有这个类名移除,没有就添加
JQuery中的入口函数
原生的window.onload事件是页面中所有资源加载完执行
入口函数仅仅是等DOM树加载完就执行
$(document).ready(function(){
})
//简写
$(function(){
})
操作标签的属性
- 设置
$("div").attr("id","box"); $("div").attr("pic","10086");
- 获取
$("div").attr("pic");
- 移除
$("div").removeAttr("id");
操作表单的相关属性
prop 针对selected 、checked、disabled
- 获取
$("input").prop("disabled"); //也可以这样 $('input').[0].disabled;
- 设置
$("input").prop("checked",true);
操作标签的内容
- 设置
$("div").text("<h1>哈哈哈</h1>");
- 获取
$("div").text();
操作元素的内容
- 设置
$("div").html("<h1>哈哈哈</h1>");//这个会渲染
- 获取
$("div").html();//这个会渲染
操作表单元素的内容
- 设置
$("input").val("发送");
- 获取
$("input").val();
JQuery动画
基本动画
- 缩放
//语法 对象.show([运动时间(毫秒)],[运动线型],[fn]) 对象.hide([运动时间(毫秒)],[运动线型],[fn]) 对象.toogle([运动时间(毫秒)],[运动线型],[fn]) 切换
- 上下
//语法 对象.slideDown([运动时间(毫秒)],[运动线型],[fn]) 对象.slideUp([运动时间(毫秒)],[运动线型],[fn]) 对象.slideToogle([运动时间(毫秒)],[运动线型],[fn]) 切换
- 淡入淡出
//语法 对象.fadeIn([运动时间(毫秒)],[运动线型],[fn]) 对象.fadeOut([运动时间(毫秒)],[运动线型],[fn]) 对象.fadeToogle([运动时间(毫秒)],[运动线型],[fn]) 切换
自定义动画
animate(params,[speed],[easing],[fn])
//param:需要传入一个对象。(动画属性集合)
$("div").animate({
width:300,
height:300,
opatiy:1;
},3000)
停止动画
对象.stop(clearQueue,jumpToend);
clearQueue--true:清空所有动画
clearQueue--false:清空当前运行的一个动画(默认)
jumpToend--true:停止当前动画,并立刻运动到目标
jumpToend--false:停止动画,保持当前停止状态,不会运动到目标(默认)
JQuery动态操作元素
动态创建
$("< li>")
动态追加
-
向父元素最后面追加
新创建的Jquery对象.appendTo($(“父元素选择器或者父元素的jquery对象”));
父元素jQuery对象.apeend(新创建的jQuery对象);
var $newLi=$('<li></li>'); $newLi.appendTo($("ul")); //也可以这样 $("ul").append($newLi);
-
向父元素最前面追加
新创建jQuery对象.prependTo(‘父元素选择器’);
父元素jQuery对象.prepend(新创建的jQuery对象);
var $newLi=$('<li></li>'); $newLi.prependTo($("ul")); //也可以这样 $("ul").prepend($newLi);
动态删除
.remove()
//删除页面中的h2
$("h2).remove()
清空元素
.empty(); //推介使用,清空内部所有的元素及元素相关的事件
.html(""); //仅仅清空内部元素,不清内部中的元素事件
克隆元素
.clone(布尔值); 返回克隆好的元素 /false//表示仅仅克隆内容 true//克隆内容和事件/
JQuery操作元素
JQuery操作元素大小
- 获取
- 获取内容大小
对象.width()/height() - 获取内容+padding大小
对象.innerWidth()/innerHeight() - 获取内容+padding+margin大小
对象.outerWidth()/outerHeight()
- 获取内容大小
JQuery操作元素位置
对象.offset();–返回的是一个对象(有top/left属性)/且参照文档
对象.offset().top;
对象.position();–返回一个对象/参照上级元素
操作卷曲的页面位置
- 获取
对象.scrollTop()/scrollLeft();–返回数字 - 设置
对象.scrollTop(数字)/scrollLeft(数字);
对象.click(function(){
//如果不设置动画,直接给window注册
$(window).scrollTop(0);
//如果设置动画,给html/body设置
$('html,body').animate({
scrollTop:0;
})
})
操作元素事件
简单方式注册事件
$(btn).click(function(){
alert(1);
});
//底层
$(btn).on('click',function(){
alert(1);
});
//底层
//事件源.addEventListener('事件',事件处理程序,是否捕获);
jquery事件委托
jquery对象.on(事件名,选择器,事件处理程序)
$('div').on('click','p',function fn1(){
//this--所点的子孙元素(DOM)
alert($(this).text());
})
移除事件
- 简单方式解绑
$('div').off('click',fn2);
- 事件监听解绑
$('div').off('click','p',fn2);
查看文档
bind和unbind注册事件
delegate实现事件委托
触发事件
对象.trigger(‘click’);
事件对象
- 获取
事件处理程序中的第一个形参 - 公共属性和方法
- 属性
e.target - 方法
阻止默认行为:e.preventDefault();
停止冒泡:e.stopPropagation();
- 属性
js操作视频和音频
<audio src="ss.mp3"></audio>
<button id="play">播放</button>
<button id="pause">暂停</button>
$("#play").click(function(){
$('audio').[0].load();
$('audio').[0].paly();//jq中没有操作音频视频的方法
})
pause(); //暂停
play(); //播放
load(); //重新加载
链式编程
调用一些方法来做设置操作时,方法结束后返回调用的对象,以便继续使用其他方法
var obj={
name:'zs',
age:1,
sing:function(){
console.log('嗯哼个');
},
da:function(){
console.log('chulai');
}
}
obj.sing();
obj.da();
//这么写不行,因为方法调用返回值为undefind
obj.sing().da();
//给方法加return this;就可以了
obj.sing().da();
var obj={
name:'zs',
age:1,
sing:function(){
console.log('嗯哼个');
return this;
},
da:function(){
console.log('chulai');
}
}
end方法回到链式上的上一个jq对象
$('li')//li对象
.eq(1).css('color','red')//第二个li对象
.parent().css('color','yellow')//父级对象
.end(); //回到eq(1)对象
多库共存
如果 被 其 他 库 中 的 被其他库中的 被其他库中的覆盖了,解决办法
- 用jquery代替
- dt= . n o C o n f l i c t ( ) ; / / 把 .noConflict();//把 .noConflict();//把的权限转让给新的变量
zepto
设计目的是提供JQuery的类似API,有一个5-10k的通用库,分模块引入
swiper
强大的触摸滑动插件
ECMAScript 6
是继ES4和ES5之后的js语言规范,提供更加方便的新语法弥补js语言本身的缺陷
有兼容问题
二. ECMAScript 6 新增语法
- let 和 const
- 解构赋值
- 函数 (箭头函数)
2.1 let 和 const
-
let
-
let 定义变量,变量不可以重名,必须先定义再使用
-
具有块级作用域
-
没有变量提升
-
代码演示
let age = 18; { // 外部无法score,因为有块级作用域 let score = 100; } for (let i = 0; i < 10; i++) { // i 只能在此范围内使用,因为有块级作用域 }
-
-
const
-
常量一旦初始化,不可以重新赋值
-
const 定义常量,常量不可以重名,必须先定义再使用
-
具有块级作用域
-
没有变量提升
-
代码演示
// 常量名一般大写 const PI = 3.1415926; // 报错,常量定义必须进行初始化 const MAX;
-
-
小结
关键字 变量提升 块级作用域 其它 let × √ 先定义再使用,不可以重名 const × √ 先定义再使用,不可以重名 var √ × 直接使用,可以重名
2.2 解构赋值
- 数组的解构
- 对象的解构
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
2.2.1 数组的解构
方便获取数组中的某些项
let arr = [5, 9, 10];
let [a, b, c] = arr;
console.log(a, b, c); // 输出 5 9 10
2.2.2 对象的解构
- 方便解析对象中的某些属性的值
// 默认情况获取到的变量需要和对象的属性同名
let obj = {foo: 'aaa', bar: 'bbb'};
let { foo, bar } = obj;
// 更改变量的名称
let obj = {foo: 'aaa', bar: 'bbb'};
let { foo: a, bar: b } = obj;
- 解构的过程可以进行模式匹配
let obj = {
name: 'zs',
age: 18,
dog: {
name: 'BYD',
age: 1
}
}
// 通过模式匹配,获取 dog 的 name 和 age
// dog 是匹配源数据中的模式
let { dog: { name, age } } = obj;
- 对象解构在实际中的应用
// 假设从服务器上获取的数据如下
let response = {
data: ['a', 'b', 'c'],
meta: {
code: 200,
msg: '获取数据成功'
}
}
// 如何获取到 code 和 msg
let { meta: { code, msg } } = response;
2.4 函数
2.4.1 箭头函数
ES6 中允许使用箭头定义函数 (=>),目的是简化函数的定义并且里面的this也比较特殊。
-
箭头函数的定义
let fn = x => x * 2; // 等同于 let fn = function (x) { return x; }
如果箭头函数的只有一个参数可以省略小括号,否则参数的小括号不可以省略
let fn = (x, y) => x + y; // 等同于 let fn = function (x, y) { return x + y; }
如果箭头函数的代码块中不止一条语句的话,不能省略大括号,如果需要返回值,必须添加 return
let fn = (x, y) => { console.log(arguments); x = 2 * x; y = 2 * y; return x + y; }
-
箭头函数不可以作为构造函数使用
-
箭头函数内部没有 arguments
2.4.2 参数的默认值
ES6 之前函数不能设置参数的默认值
// ES5 中给参数设置默认值的变通做法
function fn(x, y) {
y = y || 'world';
console.log(x, y);
}
// ES6 中给函数设置默认值
function fn(x, y = 'world') {
}
2.4.3 rest 参数
rest 参数:剩余参数,以 … 修饰最后一个参数,把多余的参数都放到一个数组中。可以替代 arguments 的使用
// 求一组数的最大值
function getMax(...values) {
let max = values[0];
for (let i = 0; i < values.length; i++) {
if (max < values[i]) {
max = values[i];
}
}
return max;
}
// 调用
console.log(getMax(6, 1, 100, 9, 10));
注意:rest 参数只能是最后一个参数
三. 内置对象的扩展
- Array 的扩展
- String 的扩展
- Number 的扩展
- Set
3.1 Array 的扩展
-
扩展运算符
扩展运算符,可以看成 rest 参数的逆运算,也是 … 可以把数组中的每一项展开
// 合并两个数组 let arr1 = [1, 2]; let arr2 = [3, 4]; let arr3 = [...arr1, ...arr2]; // 把数组展开作为参数,可以替代 apply // 求数组的最大值 let arr = [6, 99, 10, 1]; let max = Math.max(...arr);
-
Array.from()
把伪数组转换成数组
let fakeArr = { 0: 1, 1: 2, 2: 3, length: 3 }; let arr = Array.from(fakeArr); console.log(arr);
-
数组实例的 find() 和 findIndex()
find 找到数组中第一个满足条件的成员并返回该成员,如果找不到返回undefined。
findIndex 找到数组中第一个满足条件的成员并返回该成员的索引,如果找不到返回 -1。
// 找到数组中的第一个小于 0 的数字 let arr = [1, 3, -5, 6, -2]; let result = arr.find((x) => x < 0); // 等同于 let result = arr.find(function (x) { return x < 0; }); // find 回调函数有 3 个参数 arr.find(function (item, index, ar) { // item 当前的值 // index 当前的值对应的索引 // ar 原数组 });
findIndex 的使用和 find 类似
-
数组实例的 includes()
判断数组是否包含某个值,返回 true / false
3.2 String的扩展
-
模板字符串
模板字符串解决了字符串拼接不便的问题(内容太长需要换行,拼接多个变量)
模板字符串使用反引号 ` 括起来内容
let name = 'zs'; let age = 18; // 拼接多个变量,在模板字符串中使用占位的方式,更易懂 let str = `我是${name},今年${age}`; // 内容过多可以直接换行 let html = ` <div> <ul> <li>itheima</li> </ul> </div> `;
-
includes(), startsWith(), endsWith()
includes()
返回布尔值,表示是否找到了参数字符串startsWidth()
返回布尔值,表示参数字符串是否在原字符串的头部endsWith()
返回布尔值,表示参数字符串是否在原字符串的尾部。
-
repeat()
repeat
方法返回一个新字符串,表示将原字符串重复n
次。let html = '<li>itheima</li>'; html = html.repeat(10);
3.3 Number的扩展
ES6 将全局方法parseInt()
和parseFloat()
,移植到Number
对象上面,行为完全保持不变。
- Number.parseInt()
- Number.parseFloat()
3.4 Set
Set 是 ES6 中新增的内置对象,类似于数组,但是成员的值都是唯一的,没有重复的值(可以实现数组去重)。
// Set 可以通过一个数组初始化
let set = new Set([1, 2, 1, 5, 1, 6]);
// 数组去重
let arr = [...set];
- Set 的成员
size
:属性,获取set
中成员的个数,相当于数组中的length
add(value)
:添加某个值,返回 Set 结构本身。delete(value)
:删除某个值,返回一个布尔值,表示删除是否成功。has(value)
:返回一个布尔值,表示该值是否为Set
的成员。clear()
:清除所有成员,没有返回值。
ES6模块规则化
export 导出:变量、函数、类
import 导入: 自定义导入名称;解构赋值
// 导出变量
export let abc=123;
export let info=456;
// 导出函数
export function foo(){
console.log('foo)
}
// 导出类
export class Cat{
constructor(name){
this.name=name
}
}
class Dog{
constructor(name){
this.name=name
}
}
let fn = function(){
console.log('fn')
}
export { Dog,fn }
//在模块中默认的导出只能有1个,默认导出在导入时可以自定义名称。例如kitty
export default calss {
constructor(msg){
this.msg=msg
}
}
// 导入
import Kitty,{abc, info, foo, Cat, Dog, fn} from 导出文件路径
foo()
let cat = new Cat('tom')
console.log(cat)
let dog = new Dog('gou')
console.log(dog)
let k = new Kitty();
四. ECMAScript 6 降级处理
因为 ES6 有浏览器兼容性问题,可以使用一些工具进行降级处理,例如:babel
-
降级处理 babel 的使用步骤
-
安装Node.js
-
命令行中安装 babel
-
配置文件
.babelrc
-
运行
-
-
安装 Node.js
-
在命令行中,安装 babel
npm install @babel/core @babel/cli @babel/preset-env
-
配置文件
.babelrc
{ "presets": ["@babel/preset-env"] }
-
在命令行中,运行
# 把转换的结果输出到指定的文件 babel index.js -o test.js # 把转换的结果输出到指定的目录 babel src -d lib
-
参考:babel官网
五. 扩展阅读
服务端开发基础(node)
浏览器的执行过程
- 用户打开浏览器
- 地址栏输入我们需要访问的网站网址(
URL
) - 浏览器通过
DNS 服务器
获取即将访问的网站IP 地址
- 浏览器发起一个对这个 IP地址的
请求
- 服务端监听指定的
端口
的服务器软件接收到这个请求,进行相应的处理 - 服务端将处理完的结果返回给客户端浏览器(
响应
) - 浏览器将服务端返回的结果呈现到界面上
配置web服务器
安装和配置 Apache 服务器
网络的基础概念
什么是 Web 服务器
- 服务器(提供服务)指的就是一台安装特定的软件的公共计算机,用于专门用于提供特定的服务。
- 按照服务类型的不同,又划分为:Web 服务器、数据库服务器、文件服务器等等。
- 客户端(使用服务)指的是在一次服务过程中使用这个服务的设备(网络端点)。
- 目前咱们最常见的客户端就是浏览器
- Web 服务器,提供了 Web 服务器的计算机
- 常见的 Web 服务器软件:Apache、IIS、Tomcat
C/S 与 B/S
应用软件架构一般分为两类:
- B/S 架构:Browser(浏览器) ←→ Server(服务器),这种软件都是通过浏览器访问一个网站使用,服务器提供数据存储等服务。
- C/S 架构:Client(客户端) ←→ Server(服务器),这种软件通过安装一个软件到电脑,然后使用,服务器提供数据存储等服务。
IP 地址
Internet Protocol Address
- 作用就是标识一个网络设备(计算机、手机、电视)在某一个具体的网络当中的地址。
- 设备在某一个网络中的地址,目前最常见的格式:
[0-255].[0-255].[0-255].[0-255]
即为四个 0-255 的数字组成。 - 127.0.0.1 是本地回环地址
单个网络情况
在单个局域网下,结构非常简单,就是我们所连接的网络设备(网关)给我们分配了一个地址,在这个范围之内我们都可以通过这个地址找到我们的这个设备。
如果设备没有连接任何网络情况下,我们会有一个本地回环地址 127.0.0.1
端口
计算机本身是一个封闭的环境,就像是一个大楼,如果需要有数据通信往来,必须有门,这个门在术语中就叫端口,每一个端口都有一个编号,每台计算机只有 65536 个端口(0-65535)。
一般我们把“占门”的过程叫做监听
端口号的作用,是标示计算机内的某个软件
可以通过在命令行中运行: netstat -an
命令监视本机端口使用情况
参考链接:
- https://baike.baidu.com/item/%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E5%8F%A3
- https://baike.baidu.com/item/%E7%AB%AF%E5%8F%A3
http
默认的端口80
https
默认的端口是443
域名
由于 IP 地址都是没有规律的一些数字组成的,很难被人记住,不利于广泛传播,所以就有人想出来要给 IP 起名字(别名)。
域名是需要花钱注册的
- 特殊的域名
localhost
含义为本地主机,对应127.0.0.1 。这是一个保留域名,主要用于本地测试。
- 顶级域名(了解)
.com: 商业机构
.cn: 中国国家、地区域名 .hk,
.gov: 政府网站。
.org: 机构。
.edu: 教育网站。
.net: 网络服务商。
.mil: 军事。
DNS
通过宽带运营商提供的服务器解析一个域名背后对应的 IP,这个过程叫做 DNS 寻址,帮你完成 DNS 寻址过程的服务器叫做 DNS 服务器。
hosts 文件
操作系统在发起对 DNS 服务器的查询请求之前,会优先检查本机的 hosts 文件。如果这个文件中包含了对当前需要解析的域名的配置,则不再发起对 DNS 服务器的请求,直接使用 hosts 文件中的配置。
文件所在路径:
- Windows:
C:\Windows\System32\drivers\etc\hosts
- macOS:
/etc/hosts
注意:
- 本机的 hosts 文件配置只能到影响本机的 DNS 寻址
- 只有以管理员权限运行的编辑器才有权利修改
hosts
文件
URL
URL(Uniform Resource Locator),统一资源定位符,通俗点来说就是表示网络当中某一个网页的完整访问地址,它具有一定的格式:
例如:http://itcast.cn:80/schools/students?id=18&name=zs#photo
协议://主机地址[:端口]/路径?查询字符串#fragment
Node.js介绍
Node.js 是什么
以下引自 Node.js 官网:
Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine.
- 是 JavaScript 的,一种运行环境
- 能解析和执行 JavaScript 代码(严格来说应该是 ECMAScript 代码)
- 构建于 Chrome V8 JavaScript 引擎之上
- 为 JavaScript 提供了服务端编程的能力
- 文件IO
- 网络IO
- 从技术角度它的能力和 Java、PHP、Python、Perl、Ruby 等服务端技术类似
- 课后参考 Node.js 简史
Node.js 特点
- 事件驱动
- 非阻塞 IO(异步) 模型
- 单线程
- 跨平台
Node.js 能做什么
- Web 服务器
- 命令行工具
- 网络爬虫
- 桌面应用程序开发(Electron)
- 课外阅读
- Node 打破了过去 JavaScript 只能在浏览器中运行的局面
- 前后端编程环境统一,大大降低了前后端语言切换的代价
知乎 - JavaScript能做什么,该做什么?
Atwood’s Law: any application that can be written in JavaScript, will eventually be written in JavaScript.
凡是能用 JavaScript 写出来的,最终都会用 JavaScript写出来。
Node.js 中的 JavaScript
-
没有 BOM、DOM
-
ECMAScript
-
全局成员
-
Node.js 为 JavaScript 提供的服务器级别的 API
- 文件读写
- 网络通信
- http 服务器
浏览器中的 JavaScript
- ECMAScript
- BOM
- DOM
模块系统
模块的通讯规则
导出模块 module.exports
导入模块 require
exports
和module.exports
的区别module.exports
- 每个模块中都有一个
module
对象 - module 对象中有一个
exports
对象,模块最终导出的是此对象
- 每个模块中都有一个
exports
- Node.js 为了方便,同时在每一个模块中都提供了一个成员叫:
exports
exports
指向了module.exports
,exports = module.exports
- Node.js 为了方便,同时在每一个模块中都提供了一个成员叫:
模块分类
在 Node 中对不模块的一个具体分类,一共就三种类别:
- 核心模块
- 由 Node 本身提供,具名的,例如
fs
文件操作模块、http
网络操作模块
- 由 Node 本身提供,具名的,例如
- 第三方模块
- 由第三方提供,使用的时候我们需要通过 npm 进行下载然后才可以加载使用,例如:
mime
、art-template
、marked
- 注意:不可能有第三方包的名字和核心模块的名字是一样的,否则会造成冲突
- 由第三方提供,使用的时候我们需要通过 npm 进行下载然后才可以加载使用,例如:
- 用户模块(自己写的)
- 我们在文件中写的代码很多的情况下不好编写和维护,所以我们可以考虑把文件中的代码拆分到多个文件中,那这些我们自己创建的文件就是用户模块
注意:
- 我们在文件中写的代码很多的情况下不好编写和维护,所以我们可以考虑把文件中的代码拆分到多个文件中,那这些我们自己创建的文件就是用户模块
- 执行该命令前,应该先切到项目文件夹,并且项目文件夹不能为中文。
- 对于第三方模块,我们都是
npm install
命令进行下载的,放到项目根目录下的node_modules
目录。
模块的加载机制
Node.js 中的模块化遵守 CommonJS 规范,CommonJS 是模块化的一种规范,Node.js 中实现了这种规范。
模块的加载机制
- 如果不是文件模块,也不是核心模块
- node 会去 node_modules 目录中找(找跟你引用的名称一样的目录),例如这里
require('underscore')
- 如果在 node_modules 目录中找到
underscore
目录,则找该目录下的package.json
文件 - 如果找到
package.json
文件,则找该文件中的main
属性,拿到 main 指定的入口模块 - 如果过程都找不到,node 则取上一级目录下找
node_modules
目录,规则同上 - 如果一直找到代码文件的根路径还找不到,则报错
包与npm以及yarn
npm
npm
全称Node Package Manager
(node包管理器),它的诞生是为了解决 Node 中第三方包共享的问题。npm
不需要单独安装。在安装Node的时候,会连带一起安装npm
。- 官网
常用命令
-
查看
npm
版本npm --version yarn --version
-
升级
npm
npm install npm --global
-
安装yarn
npm install -g yarn
-
初始化
package.json
npm init -y yarn init
-
安装第三方包
npm install 包名 npm install 包名 包名 npm install 包名@版本号 yarn add 包名@version
-
从 package.json 安装依赖
npm install yarn
-
安装指定包到依赖或者开发依赖
npm install --save [package] yarn add [package] npm install --save-dev [package] yarn add [package] [--dev/-D]
-
安装包到全局
npm install --global [package] yarn global add [package]
-
重新下载所有包
npm reubild yarn install --force
-
卸载包
npm uninstall [package] npm uninstall --save [package] npm uninstall --save-dev [package] yarn remove [package]
-
升级包
rm -rf node_modules && npm install yarn upgrade
-
清除缓存
npm cache clean -force yard cache clean
-
运行指令
npm run 指令 yarn run 指令 如果是start可以省略
全局安装和本地安装
-
本地安装
指的是将一个包下载到当前项目的
node_modules
子目录,然后只有在项目目录之中,才能调用这个包。 -
全局安装
指的是将一个模块安装到系统目录中,各个项目都可以调用。一般来说,全局安装只适用于工具模块。
演示全局安装的工具
- http-server
https://github.com/indexzero/http-server#readme
- nodemon
http://nodemon.io/
- less
http://lesscss.org/
- browser-sync
https://browsersync.io/
切换 npm 镜像源
-
npm 存储包文件的服务器在国外,有时候会被墙,速度很慢,所以我们需要解决这个问题。
-
国内淘宝的开发团队把 npm 在国内做了一个备份,网址是:http://npm.taobao.org/。
# 下载包的时候切换源 npm install jquery --registry=https://registry.npm.taobao.org # 全局设置 npm config set registry https://registry.npm.taobao.org # 原始的路径 # https://registry.npmjs.org/
package.json
- 每个项目的根目录下面,一般都有一个
package.json
文件 package.json
定义了这个项目所需要的各种模块,以及项目的配置信息npm install
命令根据这个配置文件,自动下载所需的模块,也就是配置项目所需的运行和开发环境。- package
web开发
HTTP 协议简介
浏览器和 Web 服务器是如何通信的?
- 浏览器和 Web 服务器通信的过程就和打电话的过程一样。
- a 和 b 打电话,a 先要有 b 的手机号码 (IP和端口)
- a 给 b 拨打电话
- b 的电话响起,b 判断自己是否有空接听电话
- b 如果有空,接电话,双方可以通信(建立好通信的链接)
- 通信的过程双方要使用同样的语言说话
- 说话结束挂掉电话
- 浏览器和 Web 服务器通信
- 浏览器中输入 IP 和 端口
- 浏览器向服务器要求通信(想要建立通信的链接)
- 服务器判断是否有资源处理该浏览器的通信
- 如果服务器有资源处理,则建立一个通信的链接
- 链接建立好以后,浏览器向服务器发送 HTTP 请求,服务器处理请求,并返回 HTTP 响应
- 通信结束后,服务器关闭连接
HTTP 协议概述
- HTTP(HyperText Transfer Protocol) 超文本传输协议
- HTTP 是一种能够获取如 HTML 这样的网络资源的 protocol (通讯协议)。
- 是一种 client-server 同时要遵守的协议
- 请求通常是由像浏览器这样的接受方发起的
GET 和 POST 区别
- GET
- 获取内容
- get 请求的时候,可以在 url 上携带少量的数据
- http://www.baidu.com/s?wd=http&w=q
- ?wd=http&w=q 查询字符串
- 但是不要使用 get 请求携带隐私数据
- POST
- 提交数据
- POST 请求的数据,在请求体
- 实现登录,携带隐私数据的时候,应该使用 POST 请求
- 发送大量数据
请求报文
由三部分组成:请求行、请求头、请求体
浏览器 请求服务器上的 index.html,如果 index.html 连接了其它文件,浏览器再次发送请求,获取其它文件。
-
请求行
- 请求方法(常见的 GET 和 POST)
- 请求路径
- 协议版本
GET / HTTP/1.1 GET /index.html HTTP/1.1
-
请求头
- 由键值对组成
Host: 127.0.0.1 浏览器可以解析的文件类型 Accept: text/html,application/xhtml+xml,application/xml;q=0.9 Cookie: Hm_lvt_743362d4b71e22775786fbc54283175c=1530695737 携带了客户端的信息(操作系统和浏览器) User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36 x-
POST 请求的时候会有另一个请求头
// 告诉服务器,post 过去的数据的格式长什么样子 name=zs&pwd=123456 Content-Type: application/x-www-form-urlencoded Content-Length: 2952
-
请求体
- GET 请求没有请求体
- POST 请求有请求体
name=zs&pwd=123456
-
使用 chrome 监视请求
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g2VPCoeL-1588212489843)(/Users/wangjing/Documents/js/node/06-sql%E8%AF%AD%E6%B3%95/01-%E8%AE%B2%E4%B9%89/assets/1543976242956.png)]
响应报文
响应报文由三部分组成:响应行、响应头、响应体
-
响应行
- 协议版本
- 状态码
- 状态码描述
HTTP/1.1 404 Not Found HTTP/1.1 200 OK
-
响应头
由键值对组成
Content-Length: 51866 // 服务器告诉浏览器,发送给你的是什么类型的文件 Content-Type: text/html Server: Apache/2.4.37 (Win64)
-
响应体
返回的主体内容,如果请求的是网页返回网页的内容,如果请求的是图片返回图片的内容
请求的方法
-
GET
-
POST
-
PUT
-
DELETE
-
……
querystring 模块
http://nodejs.cn/api/querystring.html
-
解析与格式化 URL 查询字符串,或者请求体中的数据
// name=zs&pwd=12345 let body = 'name=zs&pwd=12345'; const qs = require('querystring'); body = qs.parse(body); //{ // name: 'zs', // pwd: '12345' //}
最简单的 Web 服务器
// 0. 加载 http 核心模块
const http = require('http')
// 1. 创建服务器,得到 Server 实例
const server = http.createServer()
// 2. 监听客户端的 request 请求事件,设置请求处理函数
server.on('request', (request, response) => {
// request.header
console.log('收到客户端的请求了')
})
// 3. 绑定端口号,启动服务器
// 真正需要通信的应用程序
// 如何从 a 计算机的 应用程序 通信到 b 计算机的 应用程序
// ip 地址用来定位具体的计算机
// port 端口号用来定位具体的应用程序
// 联网通信的应用程序必须占用一个端口号,同一时间同一个端口号只能被一个应用程序占用
// 开发测试的时候使用一些非默认端口,防止冲突
server.listen(3000, function () {
console.log('Server is running at port 3000.')
})
很傻的服务器
Node 服务器不同于 Apache,默认能力非常的简单,一切请求都需要自己来处理。
// 0. 加载 http 核心模块
const http = require('http')
// 1. 创建服务器,得到 Server 实例
const server = http.createServer()
// 2. 监听客户端的 request 请求事件,设置请求处理函数
// req 请求对象(获取客户端信息)
// res 响应对象(发送响应数据)
// end() 方法
server.on('request', (req, res) => {
// 发送响应数据
res.write('hello')
res.write(' hello')
// 数据写完之后,必须告诉客户端,我的数据发完了,你可以接收处理了
// 否则客户端还是会一直等待
// 结束响应,挂断电话
res.end()
})
// 3. 绑定端口号,启动服务器
// 真正需要通信的应用程序
// 如何从 a 计算机的 应用程序 通信到 b 计算机的 应用程序
// ip 地址用来定位具体的计算机
// port 端口号用来定位具体的应用程序
// 联网通信的应用程序必须占用一个端口号,同一时间同一个端口号只能被一个应用程序占用
// 开发测试的时候使用一些非默认端口,防止冲突
server.listen(3000, function () {
console.log('Server is running at port 3000.')
})
根据不同 url 地址处理不同请求
网站中的资源都是通过 url
地址来定位的,所以我就可以在请求处理函数获取客户端的请求地址,然后根据不同的请求地址处理不同的响应。
// 0. 加载 http 核心模块
const http = require('http')
// 1. 创建服务器,得到 Server 实例
const server = http.createServer()
// 2. 监听客户端的 request 请求事件,设置请求处理函数
// req 请求对象(获取客户端信息)
// res 响应对象(发送响应数据)
// end() 方法
// 任何请求都会触发 request 请求事件
// /a /b /c /dsanjdasjk
// req 请求对象中有一个属性:url 可以获取当前客户端的请求路径
server.on('request', (req, res) => {
// console.log(req.url)
// 127.0.0.1:3000/abc
// 一切请求路径都始终是以 / 开头
// / index page
// /login login page
// /about about me
// 其它的 404 Not Found.
// res.end('index page')
const url = req.url
// 通常情况下,都会把 / 当作首页
// 因为用户手动输入地址,不加任何路径,浏览器会自动补上 / 去请求
if (url === '/') {
console.log('首页')
res.end(`
<h1>首页</h1>
<ul>
<li>
<a href="/login">登陆</a>
</li>
<li>
<a href="/reg">注册</a>
</li>
</ul>
`)
} else if (url === '/login') {
console.log('登陆')
res.end('login page')
} else if (url === '/reg') {
console.log('注册')
res.end('reg page')
} else {
console.log('404 不认识')
res.end('404 Not Found.')
}
})
server.listen(3000, function () {
console.log('Server is running at port 3000.')
})
解决中文乱码问题
-
html 文件中的
<meta charset="UTF-8" />
- html 文件需要如果声明了 meta-charset 则可以不写 Content-Type
-
响应头的
Content-Type
- 根据不同的内容类型所对应的数据也不一样,具体查询:http://tool.oschina.net/commons
// 设置响应头 response.setHeader('Content-Type', 'text/html; charset=utf-8');
-
建议每个响应都告诉客户端我给你发送的 Content-Type 内容类型是什么
处理页面中的多个请求
/**
* http 结合 fs 发送文件内容
*/
const http = require('http')
const fs = require('fs')
const server = http.createServer()
server.on('request', (req, res) => {
const url = req.url
console.log(url)
if (url === '/') {
fs.readFile('./views/index.html', (err, data) => {
if (err) {
return res.end('404 Not Found.')
}
// 响应数据类型只能是:字符串 和 二进制数据
// TypeError: First argument must be a string or Buffer
// res.end(123)
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.end(data)
})
} else if (url === '/css/main.css') {
fs.readFile('./views/css/main.css', (err, data) => {
if (err) {
return res.end('404 Not Found.')
}
// 响应数据类型只能是:字符串 和 二进制数据
// TypeError: First argument must be a string or Buffer
// res.end(123)
res.setHeader('Content-Type', 'text/css; charset=utf-8')
res.end(data)
})
} else if (url === '/js/main.js') {
fs.readFile('./views/js/main.js', (err, data) => {
if (err) {
return res.end('404 Not Found.')
}
// 响应数据类型只能是:字符串 和 二进制数据
// TypeError: First argument must be a string or Buffer
// res.end(123)
res.setHeader('Content-Type', 'application/x-javascript; charset=utf-8')
res.end(data)
})
} else if (url === '/img/ab2.jpg') {
fs.readFile('./views/img/ab2.jpg', (err, data) => {
if (err) {
return res.end('404 Not Found.')
}
// 响应数据类型只能是:字符串 和 二进制数据
// TypeError: First argument must be a string or Buffer
// res.end(123)
// 只有文本类型需要加 charset 编码
// 图片不是文本,所以不用加编码
res.setHeader('Content-Type', 'image/jpeg')
res.end(data)
})
}
})
server.listen(3000, () => {
console.log('running...')
})
统一处理静态资源
-
自己处理
- 在网页中给所有的外部链接 加一个标示 /public/
- 在node中,判断当前请求的路径,是否包含/public/
- 为了方便找到文件的路径,把css、images文件夹放到了 新建的public文件夹中
- 读取文件,返回响应
-
使用第三方模块
https://github.com/broofa/node-mime
能够根据后缀名生成 Content-Type 的值
-
下载模块
# 创建package.json -- 项目文件夹不能有中文 npm init -y npm install mime
-
使用模块
const mime = require('mime'); mime.getType('txt'); // ⇨ 'text/plain' mime.getExtension('text/plain'); // ⇨ 'txt'
-
fs.readFile() 读取文件的问题
fs.readFile(‘相对路径’)
相对路径,是相对于工作目录 — node 程序执行的目录
建议 以后 使用fs.readFile 读取文件的时候,使用绝对路径
fs.readFile(path.join(__dirname, ‘xxx’))
API 总结
请求对象 Request
- url
- method
- headers
响应对象 Response
- write
- end 向浏览器返回响应内容
- statusCode 设置状态码
- setHeader 设置响应头
静态网站与动态网站
- 静态网站
我们已经基于 Node.js 开发了一个静态网站的 web 服务器。处理的过程找到你请求对应的路径 → 读取文件 → 将文件内容响应给客户端浏览器(文件原封不动的给你)。无法满足让网页内容动起来(随着数据动态变化)的需求。
- 动态网站
动态网站的原理:不再将 HTML 固定写死,每次用户请求时,动态执行一段代码,临时生成一个用户想要的 HTML 页面。这种实现这种概念的技术有很多种:JSP、ASP.NET、PHP、Node 等等。
动态网站指的也就是每次请求时服务端动态生成 HTML 返回给用户的这种网站。
**目的:**了解服务端开发,以及某些其他对前端开发有帮助的东西。
留言本案例
发表留言
-
存储数据-使用 JSON 格式
-
要存储留言信息的话,未来会使用专业的存储数据库
-
现在先使用简化的方式来处理 – JSON 格式的数据
-
JSON 格式跟对象类似,但是 JSON 是字符串形式的数据,例如:
描述对象,属性必须使用 双引号,值如果是字符串也要使用双引号
{ "name": "小红", age: 18 }
描述数组
[ { "name": "小红", age: 18 }, { "name": "张三", age: 19 } ]
-
JSON 格式的字符串和对象之间的转换
// JSON 对象 JSON.parse() // 把JSON格式的字符串转换成js对象 JSON.stringify() // 把js对象转换成JSON格式的字符串
-
-
发表留言使用 POST 请求
-
检查页面的表单,设置 method 和 action
-
判断如果是 GET 请求,返回页面
-
如果是 POST 请求,处理表单提交
if (request.method === 'POST') { if (request.url === '/publish') { // 处理 发表留言 } }
-
-
获取 POST 过来的表单数据
表单提交数据的时候,想要提交到服务器的文本框(表单元素),都应该设置name属性
只有具有name属性的表单元素,才会提交给服务器(content=xxx)
request 读写的 data 和 end 事件
let body = ''; req.on('data', (chunk) => { body += chunk; }); req.on('end', () => { console.log(body); });
-
读取 JSON 对象,获取存储的留言数据,并添加留言
let lastMsg = msgs[msgs.length - 1]; let msg = { id: lastMsg.id + 1, img: lastMsg.img, name: body.name, content: body.content, time: new Date() }; msgs.push(msg); fs.writeFile('xx.json', JSON.stringify(msgs), () => { // 完毕 response.setHeader('Content-Type', 'text/html; charset=utf-8'); // response.end('添加完毕'); response.end('<script>alert("发送完毕");location.href="/";</script>'); });
留言列表
-
留言列表换成动态的数据列表
- HTML 页面中设置占位,{{list}}
- 加载网页
- 加载留言数据
- 动态拼接列表
- 替换掉HTML中的占位
- 把拼接的 HTML 返回给浏览器
let list = ''; msgs.forEach((item) => { list += ` <li> <img src="${item.img}" alt="" class="pic"> <div class="list_con"> <div class="time"> <strong>发表时间: <i>${item.time}</i></strong> <img src="/public/images/lj.jpg" alt=""> </div> <p><b>${item.name}:</b> ${item.content}</p> </div> </li> `; }); data = data.replace('{{list}}', list); response.end(data);
模板引擎
-
上一步中,拼接字符串麻烦,而且 js 中有 html 代码
-
模板引擎可以大大的简化页面内容的拼接
-
node.js 服务端的模板
- jade
- ejs
- art-template
-
art-template
- 前后端都可使用
- 两种语法支持
- 官网
-
art-template 的使用
-
安装
-
初始化 package.json
npm init -y
-
下载 art-template
npm i art-template
-
导入 art-template
const template = require('art-template');
-
-
语法
-
基本使用
let html = template(绝对路径, 数据对象); let html = template(path.join(__dirname, 'views/xx.html'), { title: '这是数据' });
-
输出数据
{{ title }}
-
条件输出
{{if value}} <p>{{ value }}</p> {{/if}}
-
循环输出
{{each items}} {{$index}} {{$value}} {{/each}}
-
-
-
使用模板引擎改造留言板案例
浏览器是如何请求服务器
- 用户在浏览器地址栏中输入网站域名
- 浏览器拿到该域名自动去请求 DNS服务器查询 用户输入的域名对应的 ip 地址
- 浏览器拿到 ip 地址之后,通过ip地址+端口号(HTTP默认80)和服务器建立连接(通过 三次握手 )
- 浏览器将用户输入的 url 地址通过 HTTP 协议包装成 请求报文 ,(服务器ip地址和端口号) 发送到服务器
- 当HTTP服务器接收到客户端浏览器发送过来的请求报文时候,按照 HTTP 协议将请求报文解析出来
- 然后服务器拿到请求报文中的请求信息(例如请求路径url),做相应的业务逻辑处理操作
- 当业务逻辑处理完毕之后,服务器将要发送给客户端的数据按照 HTTP 协议包装成 响应报文
- 然后服务器将响应报文数据发送给客户端浏览器
- 当浏览器接收到服务器发送给自己的响应报文数据的时候,浏览器根据 HTTP 协议将报文内容解析出来
- 浏览器拿到响应报文体中的数据开始 解析渲染html、css,执行 JavaScript
- 如果在解析的过程(从上到下)中,发现有外链的标签(link、css、img)
- 浏览器会自动对该标签指向的 路径地址 发起新的请求,同上。
Express
Express 介绍
- Express 是一个基于 Node.js 平台,快速、开放、极简的 web 开发框架。
- 丰富的 API 支持,强大而灵活的中间件特性
- Express 不对 Node.js 已有的特性进行二次抽象,只是在它之上扩展了 Web 应用所需的基本功能
- 有很多流行框架基于 Express
- Express 官网
- Express 中文文档(非官方)
- Express GitHub仓库
起步
安装
参考文档:http://expressjs.com/en/starter/installing.html
# 创建并切换到 myapp 目录
mkdir myapp
cd myapp
# 初始化 package.json 文件
npm init -y
# 安装 express 到项目中
npm i express
Hello World
参考文档:http://expressjs.com/en/starter/hello-world.html
// 0. 加载 Express
const express = require('express')
// 1. 调用 express() 得到一个 app
// 类似于 http.createServer()
const app = express()
// 2. 设置请求对应的处理函数
// 当客户端以 GET 方法请求 / 的时候就会调用第二个参数:请求处理函数
app.get('/', (req, res) => {
// send方法内部调用 response.end()
// 并且内部已经设置了 Content-Type和其它必要的响应头
res.send('hello world')
})
// 3. 监听端口号,启动 Web 服务
app.listen(3000, () => console.log('app listening on port 3000!'))
基本路由
参考文档:http://expressjs.com/en/starter/basic-routing.html
- 路由就像开车从北京-上海,出发之前可以查询走的路线,最终选择的那条路线就相当于路由
- 路由(Routing)是由一个 URL(或者叫路径标识)和一个特定的 HTTP 方法(GET、POST 等)组成的,涉及到应用如何处理响应客户端请求。
- 每一个路由都可以有一个或者多个处理器函数,当匹配到路由时,这个/些函数将被执行。
- 路由的定义的结构如下:
app.METHOD(PATH, HANDLER)
其中:
app
是 express 实例METHOD
是一个 HTTP 请求方法PATH
是服务端路径(定位标识)HANDLER
是当路由匹配到时需要执行的处理函数
下面是一些基本示例。
- 路径
- http://127.0.0.1:3000/xxxx
- app.get(‘路径’)
- 路径:域名后面的path
- 处理 get 请求
// 当你以 GET 方法请求 / 的时候,执行对应的处理函数
app.get('/', function (req, res) {
res.send('Hello World!')
})
- 处理 post 请求
// 当你以 POST 方法请求 / 的时候,指定对应的处理函数
app.post('/', function (req, res) {
res.send('Got a POST request')
})
路由的参考文档 routing guide.
处理静态资源
参考文档:http://expressjs.com/en/starter/static-files.html
-
目录结构
. ├── node_modules npm安装的第三方包目录,使用 npm 装包会自动创建 ├── public / statics页面需要使用的静态资源 │ ├── css │ ├── js │ ├── images │ └── ... ├── views 所有页面(只存储 html 文件,模板) │ ├── publish.html │ └── index.html ├── app.js 服务端程序入口文件,执行该文件会启动我们的 Web 服务器
-
express 中提供了方便的处理静态资源的方式
// 开放 public 目录中的资源
// 不需要访问前缀
app.use(express.static('public'))
// http://127.0.0.1:3000/css/index.css
// http://127.0.0.1:3000/images/lj.jpg
// http://127.0.0.1:3000/images/timg.jpg
// 开放 files 目录资源,同上
app.use(express.static('files'))
// 限制访问前缀
app.use('/public', express.static('public'))
// http://127.0.0.1:3000/public/css/index.css
// 开放 public 目录资源,限制访问前缀
app.use('/static', express.static('public'))
// 开放 public 目录,限制访问前缀
// path.join(__dirname, 'public') 会得到一个绝对路径
app.use('/public', express.static(path.join(__dirname, 'public')))
注意: express.static()
使用相对路径的时候,相对于工作目录(执行 node 程序的目录),推荐此处使用绝对路径。
留言板案例-静态 web 服务器
// 设置静态资源访问的路径
app.use('/public', express.static(path.join(__dirname, 'public')));
// 设置首页的路由
app.get('/', (request, response) => {
response.sendFile(path.join(__dirname, 'views/index.html'));
});
解析 post 请求体
参考文档:
- 在 Express 中没有内置获取表单 POST 请求体的 API
- 这里我们需要使用一个第三方包:
body-parser
安装:
npm install body-parser
配置:
var express = require('express')
// 0. 引包
var bodyParser = require('body-parser')
var app = express()
// 配置 body-parser
// 只要加入这个配置,则在 req 请求对象上会多出来一个属性:body
// 也就是说你就可以直接通过 req.body 来获取表单 POST 请求体数据了
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json());
注意: body-parser的配置要放在,设置路由之前
使用:
// 可以通过 req.body 来获取表单 POST 请求体数据
app.post('/publish', (req, res) => {
res.send(req.body);
});
留言板案例
发表留言
-
获取 post 过来的数据 - 配置body-parser
-
读取 db.json,把内容转换成js数组对象
-
构造留言对象,把对象添加到数组中
-
把留言数组转换成json字符串,写入db.json
-
提示并跳转
// 配置body-parser,解析post过来的数据,放到request.body中 app.use(bodyParser.urlencoded({ extended: false })); app.post('/publish', (request, response) => { // 1. 获取 post 过来的数据 // console.log(request.body); // 2. 读取 db.json,把内容转换成js数组对象 fs.readFile(path.join(__dirname, 'db.json'), 'utf-8', (err, data) => { if (err) throw err; let msgs = JSON.parse(data); // 3. 构造留言对象,把对象添加到数组中 let lastMsg = msgs[msgs.length - 1]; let msg = { id: lastMsg.id + 1, name: request.body.name, content: request.body.content, time: '2019-1-1 10:10:10', img: lastMsg.img }; msgs.push(msg); // 4. 把留言数组转换成字符串,写入db.json let str = JSON.stringify(msgs); fs.writeFile(path.join(__dirname, 'db.json'), str, (err) => { if (err) throw err; // 浏览器弹出提示,并跳转 response.send('<script>alert("发表成功");location.href="/";</script>'); }); }); });
留言列表
-
安装 art-template,导入模块
-
配置模板
{{ each msgs }} <li> <img src="{{ $value.img }}" alt="" class="pic"> <div class="list_con"> <div class="time"> <strong>发表时间: <i>{{ $value.time }}</i></strong> <img src="public/images/lj.jpg" alt=""> </div> <p><b>{{ $value.name }}:</b> {{ $value.content }}</p> </div> </li> {{ /each }}
-
读取 db.json,把内容转换成js的数组对象
-
使用art-template渲染模板
-
把渲染的网页,发送给浏览器
app.get('/', (request, response) => { // 读取 db.json,把内容转换成js的数组对象 fs.readFile(path.join(__dirname, 'db.json'), 'utf-8', (err, data) => { if (err) throw err; // 把 json字符串转换成数组对象 let msgs = JSON.parse(data); // 使用art-template渲染模板 let html = template(path.join(__dirname, 'views/index.html'), { msgs }); // 给浏览器发送响应 response.send(html); }); });
express 模板引擎
http://expressjs.com/en/guide/using-template-engines.html)
我们可以使用模板引擎处理服务端渲染,但是 Express 为了保持其极简灵活的特性并没有提供类似的功能。
同样的,Express 也是开放的,它支持开发人员根据自己的需求将模板引擎和 Express 结合实现服务端渲染的能力。
配置使用 art-template 模板引擎
参考文档:
这里我们以 art-template 模板引擎为例演示如何和 Express 结合使用。
安装:
npm install art-template express-art-template
配置:
const expressTPL = require('express-art-template');
// 默认模板都放在views文件夹中
// 设置html文件为模板
app.set('view engine', 'html');
// 设置模板交给谁去处理
app.engine('html', expressTPL);
使用示例:
app.get('/', function (req, res) {
// render 方法默认会去项目的 views 目录中查找 index.html 文件
// render 方法的本质就是将读取文件和模板引擎渲染这件事儿给封装起来了
// 默认模板都是html文件,这里的.html可以省略
res.render('index', {
title: 'hello world'
})
})
如果希望修改默认的 views
视图渲染存储目录,可以:
// 第一个参数 views 是一个特定标识,不能乱写
// 第二个参数给定一个目录路径作为默认的视图查找目录
app.set('views', 目录路径)
-
改造留言板案例
-
下载 art-template express-art-template
-
配置 express 模板引擎
const expressTPL = require('express-art-template'); // 设置模板的后缀 app.set('view engine', 'html'); // 设置模板交给谁去处理 app.engine('html', expressTPL);
-
使用 express 模板引擎
response.render('index', { msgs });
-
其它常见模板引擎
JavaScript 模板引擎有很多,并且他们的功能都大抵相同,但是不同的模板引擎也各有自己的特色。
大部分 JavaScript 模板引擎都可以在 Node 中使用,下面是一些常见的模板引擎。
- ejs
- handlebars
- jade
- 后改名为 pug
包与 npm
包
模块
- 模块和文件是一一对应的,一个 Node.js 文件就是一个模块
- Node.js 中的模块化遵守 CommonJS 规范,CommonJS 是模块化的一种规范,Node.js 中实现了这种规范。
- 模块的语法
- require
- module.exports
- exports
什么是包
- 包(package)是某个独立功能的封装,包是在模块基础上更深一步的抽象。简单理解:一个包中可以包含一组功能相近的模块
- 包可以使用文件夹的形式来组织
演示包
封装一个独立的数学模块,把不同的功能放到独立的模块(js 文件)中,通过一个出口文件统一导出所有模块。
- 项目中创建一个
math
文件夹 - 把不同的计算功能分别封装到一个不同的模块中:add.js、sub.js、mul.js
- 在模块中使用
modules.exports
导出一个计算的函数 - 创建一个
index.js
,导入所有模块,并导出相关成员- 注意: 包中默认导出的模块名称是
index.js
- 注意: 包中默认导出的模块名称是
package.json
如何更改默认的导出的模块名称?此时就要使用 package.json
-
创建
package.json
npm init npm init -y
-
main
main 字段指定了加载的入口文件,
require('moduleName')
就会加载这个文件。这个字段的默认值是模块根目录下面的index.js
。 -
dependencies 依赖(复数)
- 软件的版本号 jQuery@3.3.1
- 大版本.次要版本.小版本
- 小版本:当项目在进行了局部修改或 bug 修正时,修正版本号加 1
- 次要版本:当项目在原有的基础上增加了部分功能时,主版本号不变,子版本号加 1
- 大版本:当项目在进行了重大修改或局部修正累积较多,而导致项目整体发生全局变化时,主版本号加 1
"dependencies": { "art-template": "^4.13.2", "body-parser": "^1.18.3", "express": "^4.16.4", "express-art-template": "^1.0.1" }
dependencies
字段指定了项目运行所依赖的模块- 使用
npm install
可以安装所有的依赖 - 该对象的各个成员,分别由模块名和对应的版本要求组成,表示依赖的模块及其版本范围。
- 指定版本:比如
1.2.2
,遵循“大版本.次要版本.小版本”的格式规定,安装时只安装指定版本。 - 波浪号(tilde)+指定版本:比如
~1.2.2
,表示安装1.2.x的最新版本(不低于1.2.2),但是不安装1.3.x,也就是说安装时不改变大版本号和次要版本号。 - 插入号(caret)+指定版本:比如ˆ1.2.2,表示安装1.x.x的最新版本(不低于1.2.2),但是不安装2.x.x
- 指定版本:比如
- 软件的版本号 jQuery@3.3.1
-
scripts
scripts
指定了运行脚本命令的 npm 命令行缩写,比如start指定了运行npm run start
时,所要执行的命令。"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node app.js", "t": "dir c:\\" }
运行
scripts
npm run t npm run start # 只有 start 可以简化调用 npm start
一个神秘的文件夹
- 我们下载第三方包的时候,会自动把下载的第三方包,放到
node_modules
中。使用第三方包的时候直接require('第三方包的名字')
。 - 我们自己写的包也可以放到此文件夹,加载的时候直接写包名即可。
require
的加载顺序- 打印 module 对象
- 包加载的过程,按照
module.paths
中的路径一级一级往上查找 - 第一次
require()
加载完毕,会把 模块/包 缓存起来,再次require()
的时候直接从缓存加载
require 的加载机制
require
优先加载缓存中的模块- 如果缓存中没有模块,优先加载核心模块,并缓存
- 如果有相对路径,则根据路径加载文件模块,并缓存
require('./main')
省略扩展名的情况- 先加载
main.js
,如果没有再加载main.json
,如果没有再加载main.node
(c/c++编写的模块)
- 如果不是文件模块,也不是核心模块,则加载第三方模块
- node 会去 node_modules 目录中找(找跟你引用的名称一样的目录),例如这里
require('moment')
- 如果在 node_modules 目录中找到
moment
目录,则找该目录下的package.json
文件 - 如果找到
package.json
文件,则找该文件中的main
属性,拿到 main 指定的模块 - 如果过程都找不到,node 则取上一级目录下找
node_modules
目录,规则同上 - 如果一直找到代码文件的根路径还找不到,则报错
- 模块加载机制原理图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JMxsMrF5-1588212489847)(./assets/nodejs-require.jpg)]
npm
npm
全称Node Package Manager
(node 包管理器),它的诞生是为了解决 Node 中第三方包共享的问题。npm
不需要单独安装。在安装Node的时候,会连带一起安装npm
。- 官网
切换 npm 镜像源
-
npm 存储包文件的服务器在国外,速度很慢,所以我们需要解决这个问题。
-
国内淘宝的开发团队把 npm 在国内做了一个备份,网址是:http://npm.taobao.org/。
# 查看当前的源 npm config ls # registry = "https://registry.npm.taobao.org/" # 下载包的时候切换源 npm install express --registry=https://registry.npm.taobao.org # 全局设置 npm config set registry https://registry.npm.taobao.org # 原始的路径 # https://registry.npmjs.org/
常用命令
-
查看
npm
版本npm --version npm -v
-
升级
npm
npm install npm --global npm install npm -g
-
初始化
package.json
npm init -y
-
安装第三方包
npm install 包名 npm install 包名 包名 npm install 包名@版本号 # 简写 npm i 包名 # 卸载包 npm uninstall 包名
-
从缓存目录安装包
# 查看缓存目录 npm config get cache # 从缓存目录下载包 # --cache-min 后面跟的是时间,单位是分钟,超过这个时间才去服务器下载 npm install --cache-min 9999999 <package-name>
全局命令行工具
-
全局安装和本地安装
-
本地安装
指的是将一个包下载到当前项目的
node_modules
子目录,然后只有在项目目录之中,才能调用这个包。 -
全局安装
指的是将一个模块安装到系统目录中,各个项目都可以调用。一般来说,全局安装只适用于工具模块。
# 查看全局安装目录 npm config ls npm root -g # prefix 是全局安装目录 # prefix = "C:\\Users\\你的用户名\\AppData\\Roaming\\npm"
-
-
演示全局安装的工具
npm install 包名 --global npm install 包名 -g
- http-server
https://github.com/indexzero/http-server#readme
- nodemon
http://nodemon.io/
- less
http://lesscss.org/
-
browser-sync
npm install -g browser-sync
https://browsersync.io/
数据库 MySQL
数据库入门
未来我们程序中的数据为了方便管理都通过数据库来存储。
作为前端开发人员,对数据库做一定了解即可。
数据库基础知识
- 什么是数据库
- 存储数据的仓库
- 使用数据库管理数据的好处
- 方便存储、查询、修改、删除
- 关系型数据库
- MySQL
- SQL Server
- Orcale
- SQLite
- 数据表
- 二维的表,类似于Excel表
- 由行和列组成,列:字段,行:记录
- 字段的类型
- int 整数、double 浮点数、varchar(255) 字符串、text 文本、datetime 日期、float 浮点数
MySQL 的服务器
-
MySQL 安装与配置
下载地址:
- https://dev.mysql.com/downloads/windows/installer/5.7.html
参考链接:
- https://dev.mysql.com/doc/refman/5.7/en/mysql-installer.html
MySQL 的客户端
- 数据库的客户端 Navicat
- 使用 Navicat 创建数据库
- 使用 Navicat 创建表,添加数据
SQL
要在程序中对数据库进行操作需要 SQL 语句
-
什么是 SQL
- SQL 指结构化查询语言
- SQL 使我们有能力访问数据库
- 参考网站
-
执行 sql 语句
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T8ixndmo-1588212489848)(/Users/wangjing/Documents/js/node/06-sql%E8%AF%AD%E6%B3%95/01-%E8%AE%B2%E4%B9%89/assets/1544252556120.png)]
-
数据库和表的操作
-
数据库
创建
create database test;
删除
-- 删除数据库 -- 如果执行多条sql语句要带分号 drop database test;
-
数据表
建表
-- 切换数据库 use test; -- 在 test 数据库建表 create table msg ( id int auto_increment primary key, name varchar(20) not null, content text null, time datetime, img varchar(100) ) -- auto_increment 自动编号 -- primary key 主键,唯一标示一条数据
删除表
drop table msg;
-
-
增删改查
-
插入数据
INSERT INTO users (uname, upwd, uqq, uage) values('zs','123', '12345', 18) -- 如果是所有列,可以省略列名称,不推荐 INSERT INTO users values(2,'zs','123', '12345', 18)
-
修改数据
UPDATE users SET uname='zsxxx', uqq='111' WHERE uid=1 -- 如果不写条件,所有数据都被更新,建议修改的时候一定要加条件 UPDATE users SET uname='zsxxx', uqq='111'
-
删除数据
DELETE FROM users WHERE uid = 1 -- 不带条件删除表中所有数据,禁止使用 DELETE FROM users
-
查询数据
SELECT * FROM users SELECT 列1,列2 FROM users
-
导出和导入 SQL 脚本
-
导出 SQL 脚本
在数据库名字上点击右键
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Ng7EilP-1588212489850)(/Users/wangjing/Documents/js/node/06-sql%E8%AF%AD%E6%B3%95/01-%E8%AE%B2%E4%B9%89/assets/1544363426601.png)]
-
导入 SQL 脚本
在数据库名字上点击右键,点击运行 SQL 文件,选择 SQL 文件的位置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TKloHF21-1588212489851)(/Users/wangjing/Documents/js/node/06-sql%E8%AF%AD%E6%B3%95/01-%E8%AE%B2%E4%B9%89/assets/1544363543195.png)]
查询
-
条件查询
SELECT * FROM users WHERE uname='zs' AND uname='000000' SELECT * FROM users WHERE uname='zs' OR uname='ls'
下面的运算符可在 WHERE 子句中使用:
操作符 描述 = 等于 <> 不等于 > 大于 < 小于 >= 大于等于 <= 小于等于 BETWEEN…AND 在某个范围内 LIKE 搜索某种模式 -
模糊查询
SELECT * FROM users WHERE uname like '%s%'
-
in 语句
SELECT * FROM users WHERE uname in ('zs','ls')
-
排序
order by 要写在 sql 语句的最后
-- asc 默认是升序 desc 降序 SELECT * FROM users ORDER BY 字段(列) DESC -- 先根据条件获取数据,再对数据排序 SELECT * FROM users WHERE uage > 18 ORDER by 字段(列) desc
-
限制查询条数
-- 取前3条数据 SELECT * FROM users LIMIT 3 -- 降序后去3条数据 SELECT * FROM users ORDER BY id DESC LIMIT 3 -- 跳过3条,取2条 SELECT * FROM users ORDER BY id DESC LIMIT 3,2
-
获取总条数
SELECT COUNT(*) FROM users -- 修改返回数据的列名 as SELECT count(*) as sum FROM users
-
表连接
SELECT column_name(s) FROM table_name1 INNER JOIN table_name2 ON table_name1.column_name=table_name2.column_name where 条件
Node.js 中操作 MySQL
使用 mysql 第三方包
https://github.com/mysqljs/mysql
安装
npm install mysql
Hello World
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'me',
password : 'secret',
database : 'my_db'
});
connection.connect();
connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
connection.end();
增删改查
查询
基本查询:
connection.query('SELECT * FROM `books` WHERE `author` = "David"', function (error, results, fields) {
// error will be an Error if one occurred during the query
// results will contain the results of the query
// fields will contain information about the returned results fields (if any)
});
条件查询:
connection.query('SELECT * FROM `books` WHERE `author` = ?', ['David'], function (error, results, fields) {
// error will be an Error if one occurred during the query
// results will contain the results of the query
// fields will contain information about the returned results fields (if any)
});
添加
var post = {id: 1, title: 'Hello MySQL'};
var query = connection.query('INSERT INTO posts SET ?', post, function (error, results, fields) {
if (error) throw error;
// Neat!
});
console.log(query.sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'
删除
connection.query('DELETE FROM posts WHERE title = "wrong"', function (error, results, fields) {
if (error) throw error;
console.log('deleted ' + results.affectedRows + ' rows');
})
修改
connection.query('UPDATE users SET foo = ?, bar = ?, baz = ? WHERE id = ?', ['a', 'b', 'c', userId], function (error, results, fields) {
if (error) throw error;
// ...
})
连接池
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7z0Jogpl-1588212489852)(…/…/…/…/…/…/%E5%B7%A5%E4%BD%9C/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%BC%96%E7%A8%8BNode.js/%E8%B5%84%E6%96%99/nodejs%E8%AE%B2%E4%B9%89/assets/connection-pool.png)]
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'example.org',
user : 'bob',
password : 'secret',
database : 'my_db',
connectionLimit: 10 // 默认是 10 个
});
pool.getConnection(function(err, connection) {
// Use the connection
connection.query('SELECT something FROM sometable', function (error, results, fields) {
// 释放回连接池
connection.release();
// 处理错误
if (error) throw error;
// ...
});
});
封装 dbHelper.js
const mysql = require('mysql')
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: '123456',
database: 'test',
connectionLimit: 10 // 默认是 10 个
})
exports.query = (...args) => {
// 从数组中弹出最后一个元素 callback 回调函数
const callback = args.pop()
pool.getConnection((err, connection) => {
if (err) {
return callback(err)
}
connection.query(...args, function (...results) { // ...results => [err, results, fields]
// 释放回连接池
connection.release()
// 把 ...results => [err, results, fields] 展开调用 callback 继续往外抛
callback(...results)
})
})
}
Vue
什么是Vue.js
-
Vue.js 是目前最火的一个前端框架,React是最流行的一个前端框架(React除了开发网站,还可以开发手机App, Vue语法也是可以用于进行手机App开发的,需要借助于Weex)
-
Vue.js 是前端的主流框架之一,和Angular.js、React.js 一起,并成为前端三大主流框架!
-
Vue.js 是一套构建用户界面的框架,只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合。(Vue有配套的第三方类库,可以整合起来做大型项目的开发)
-
前端的主要工作?主要负责MVC中的V这一层;主要工作就是和界面打交道,来制作前端页面效果;
为什么要学习流行框架
- 企业为了提高开发效率:在企业中,时间就是效率,效率就是金钱;
- 企业中,使用框架,能够提高开发的效率;
-
提高开发效率的发展历程:原生JS -> Jquery之类的类库 -> 前端模板引擎 -> Angular.js / Vue.js(能够帮助我们减少不必要的DOM操作;提高渲染效率;双向数据绑定的概念【通过框架提供的指令,我们前端程序员只需要关心数据的业务逻辑,不再关心DOM是如何渲染的了】)
-
在Vue中,一个核心的概念,就是让用户不再操作DOM元素,解放了用户的双手,让程序员可以更多的时间去关注业务逻辑;
-
增强自己就业时候的竞争力
- 人无我有,人有我优
- 你平时不忙的时候,都在干嘛?
框架和库的区别
- 框架:是一套完整的解决方案;对项目的侵入性较大,项目如果需要更换框架,则需要重新架构整个项目。
- node 中的 express;
- 库(插件):提供某一个小功能,对项目的侵入性较小,如果某个库无法完成某些需求,可以很容易切换到其它库实现需求。
-
- 从Jquery 切换到 Zepto
-
- 从 EJS 切换到 art-template
Node(后端)中的 MVC 与 前端中的 MVVM 之间的区别
-
MVC 主要是后端的分层开发思想;把 一个完整的后端项目,分成了三个部分:
- Model:(数据层)主要负责 数据库的操作;
- View:(视图层)所有前端页面,统称为 View 层
- Controller:(业务逻辑层)主要处理对应的业务逻辑;(对于后台来说,这是开发的重点)
-
MVVM是前端页面的分层开发思想,主要关注于 视图层 分离,也就是说:MVVM把前端的视图层,分为了 三部分 Model, View, ViewModel
- Model 是 页面中,需要用到的数据
- View 是页面中的HTML结构;
- ViewModel 是 一个 中间的调度者,提供了双向数据绑定的概念;
-
为什么有了MVC还要有MVVM
- 因为 MVC是后端的开发思想,并没有明确定义前端的页面该如何开发;
- MVVM 是前端的页面的开发思想,把每个页面,分成了三个部分,同时 VM 作为 MVVM 的核心,提供了双向数据绑定的概念,前端程序员,不需要手动渲染页面了,而且,页面数据发送变化,也不需要程序员手动把 数据的变化同步到Model中;这所有的操作,都是 VM 自动完成的!
- MVVM 的可以使得开发者只关心 页面交互逻辑,不关心页面如何渲染;
Vue指令
跑马灯效果
- HTML结构:
<div id="app">
<p>{{info}}</p>
<input type="button" value="开启" v-on:click="go">
<input type="button" value="停止" v-on:click="stop">
</div>
- Vue实例:
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
info: '猥琐发育,别浪~!',
intervalId: null
},
methods: {
go() {
// 如果当前有定时器在运行,则直接return
if (this.intervalId != null) {
return;
}
// 开始定时器
this.intervalId = setInterval(() => {
this.info = this.info.substring(1) + this.info.substring(0, 1);
}, 500);
},
stop() {
clearInterval(this.intervalId);
}
}
});
Vue修饰符
事件修饰符:
-
.stop 阻止冒泡
-
.prevent 阻止默认事件
-
.capture 添加事件侦听器时使用事件捕获模式
-
.self 只当事件在该元素本身(比如不是子元素)触发时触发回调
-
.once 事件只触发一次
按键修饰符 @keyup
限制指定的键被触发执行,按键修饰符都是配合输入框使用的
- .enter
- .tab
- .esc
- .space
- .left
- .right
简易计算器案例
- HTML 代码结构
<div id="app">
<input type="text" v-model="n1">
<select v-model="opt">
<option value="0">+</option>
<option value="1">-</option>
<option value="2">*</option>
<option value="3">÷</option>
</select>
<input type="text" v-model="n2">
<input type="button" value="=" v-on:click="getResult">
<input type="text" v-model="result">
</div>
- Vue实例代码:
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
n1: 0,
n2: 0,
result: 0,
opt: '0'
},
methods: {
getResult() {
switch (this.opt) {
case '0':
this.result = parseInt(this.n1) + parseInt(this.n2);
break;
case '1':
this.result = parseInt(this.n1) - parseInt(this.n2);
break;
case '2':
this.result = parseInt(this.n1) * parseInt(this.n2);
break;
case '3':
this.result = parseInt(this.n1) / parseInt(this.n2);
break;
}
}
}
});
在Vue中使用样式
使用class样式
- 数组
<h1 :class="['red', 'thin']">这是一个邪恶的H1</h1>
- 数组中使用三元表达式
<h1 :class="['red', 'thin', isactive?'active':'']">这是一个邪恶的H1</h1>
- 数组中嵌套对象
<h1 :class="['red', 'thin', {'active': isactive}]">这是一个邪恶的H1</h1>
- 直接使用对象
<h1 :class="{red:true, italic:true, active:true, thin:true}">这是一个邪恶的H1</h1>
使用内联样式
- 直接在元素上通过
:style
的形式,书写样式对象
<h1 :style="{color: 'red', 'font-size': '40px'}">这是一个善良的H1</h1>
- 将样式对象,定义到
data
中,并直接引用到:style
中
- 在data上定义样式:
data: {
h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' }
}
- 在元素中,通过属性绑定的形式,将样式对象应用到元素中:
<h1 :style="h1StyleObj">这是一个善良的H1</h1>
- 在
:style
中通过数组,引用多个data
上的样式对象
- 在data上定义样式:
data: {
h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' },
h1StyleObj2: { fontStyle: 'italic' }
}
- 在元素中,通过属性绑定的形式,将样式对象应用到元素中:
<h1 :style="[h1StyleObj, h1StyleObj2]">这是一个善良的H1</h1>
品牌管理案例
添加新品牌
删除品牌
根据条件筛选品牌
- 1.x 版本中的filterBy指令,在2.x中已经被废除:
<tr v-for="item in list | filterBy searchName in 'name'">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.ctime}}</td>
<td>
<a href="#" @click.prevent="del(item.id)">删除</a>
</td>
</tr>
- 在2.x版本中手动实现筛选的方式:
- 筛选框绑定到 VM 实例中的
searchName
属性:
<hr> 输入筛选名称:
<input type="text" v-model="searchName">
- 在使用
v-for
指令循环每一行数据的时候,不再直接item in list
,而是in
一个 过滤的methods 方法,同时,把过滤条件searchName
传递进去:
<tbody>
<tr v-for="item in search(searchName)">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.ctime}}</td>
<td>
<a href="#" @click.prevent="del(item.id)">删除</a>
</td>
</tr>
</tbody>
search
过滤方法中,使用 数组的filter
方法进行过滤:
search(name) {
return this.list.filter(x => {
return x.name.indexOf(name) != -1;
});
}
Vue调试工具vue-devtools
的安装步骤和使用
过滤器
概念:Vue.js 允许你自定义过滤器,可被用作一些常见的文本格式化。过滤器可以用在两个地方:mustache 插值和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符指示;
私有过滤器
- HTML元素:
<td>{{item.ctime | dataFormat('yyyy-mm-dd')}}</td>
- 私有
filters
定义方式:
filters: { //私有局部过滤器,只能在当前 VM 对象所控制的 View 区域进行使用
dataFormat(input, pattern = "") { // 在参数列表中 通过 pattern="" 来指定形参默认值,防止报错
var dt = new Date(input);
// 获取年月日
var y = dt.getFullYear();
var m = (dt.getMonth() + 1).toString().padStart(2, '0');
var d = dt.getDate().toString().padStart(2, '0');
// 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日
// 否则,就返回 年-月-日 时:分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-${d}`;
} else {
// 获取时分秒
var hh = dt.getHours().toString().padStart(2, '0');
var mm = dt.getMinutes().toString().padStart(2, '0');
var ss = dt.getSeconds().toString().padStart(2, '0');
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
}
}
}
使用ES6中的字符串新方法 String.prototype.padStart(maxLength, fillString=’’) 或 String.prototype.padEnd(maxLength, fillString=’’)来填充字符串;
全局过滤器
// 定义一个全局过滤器
Vue.filter('dataFormat', function (input, pattern = '') {
var dt = new Date(input);
// 获取年月日
var y = dt.getFullYear();
var m = (dt.getMonth() + 1).toString().padStart(2, '0');
var d = dt.getDate().toString().padStart(2, '0');
// 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日
// 否则,就返回 年-月-日 时:分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-${d}`;
} else {
// 获取时分秒
var hh = dt.getHours().toString().padStart(2, '0');
var mm = dt.getMinutes().toString().padStart(2, '0');
var ss = dt.getSeconds().toString().padStart(2, '0');
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
}
});
注意:当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,即:局部过滤器优先于全局过滤器被调用!
键盘修饰符以及自定义键盘修饰符
1.x中自定义键盘修饰符【了解即可】
Vue.directive('on').keyCodes.f2 = 113;
2.x中自定义键盘修饰符
- 通过
Vue.config.keyCodes.名称 = 按键值
来自定义案件修饰符的别名:
Vue.config.keyCodes.f2 = 113;
- 使用自定义的按键修饰符:
<input type="text" v-model="name" @keyup.f2="add">
自定义指令
- 自定义全局和局部的 自定义指令:
// 自定义全局指令 v-focus,为绑定的元素自动获取焦点:
Vue.directive('focus', {
inserted: function (el) { // inserted 表示被绑定元素插入父节点时调用
el.focus();
}
});
// 自定义局部指令 v-color 和 v-font-weight,为绑定的元素设置指定的字体颜色 和 字体粗细:
directives: {
color: { // 为元素设置指定的字体颜色
bind(el, binding) {
el.style.color = binding.value;
}
},
'font-weight': function (el, binding2) { // 自定义指令的简写形式,等同于定义了 bind 和 update 两个钩子函数
el.style.fontWeight = binding2.value;
}
}
- 自定义指令的使用方式:
<input type="text" v-model="searchName" v-focus v-color="'red'" v-font-weight="900">
Vue 1.x 中 自定义元素指令【已废弃,了解即可】
Vue.elementDirective('red-color', {
bind: function () {
this.el.style.color = 'red';
}
});
使用方式:
<red-color>1232</red-color>
相关文章
- vue.js 1.x 文档
- vue.js 2.x 文档
- String.prototype.padStart(maxLength, fillString)
- js 里面的键盘事件对应的键码
- Vue.js双向绑定的实现原理
Vue.js - Day2
品牌管理案例
添加新品牌
删除品牌
根据条件筛选品牌
- 1.x 版本中的filterBy指令,在2.x中已经被废除:
<tr v-for="item in list | filterBy searchName in 'name'">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.ctime}}</td>
<td>
<a href="#" @click.prevent="del(item.id)">删除</a>
</td>
</tr>
- 在2.x版本中手动实现筛选的方式:
- 筛选框绑定到 VM 实例中的
searchName
属性:
<hr> 输入筛选名称:
<input type="text" v-model="searchName">
- 在使用
v-for
指令循环每一行数据的时候,不再直接item in list
,而是in
一个 过滤的methods 方法,同时,把过滤条件searchName
传递进去:
<tbody>
<tr v-for="item in search(searchName)">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.ctime}}</td>
<td>
<a href="#" @click.prevent="del(item.id)">删除</a>
</td>
</tr>
</tbody>
search
过滤方法中,使用 数组的filter
方法进行过滤:
search(name) {
return this.list.filter(x => {
return x.name.indexOf(name) != -1;
});
}
Vue调试工具vue-devtools
的安装步骤和使用
过滤器
概念:Vue.js 允许你自定义过滤器,可被用作一些常见的文本格式化。过滤器可以用在两个地方:mustache 插值和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符指示;
私有过滤器
- HTML元素:
<td>{{item.ctime | dataFormat('yyyy-mm-dd')}}</td>
- 私有
filters
定义方式:
filters: { // 私有局部过滤器,只能在 当前 VM 对象所控制的 View 区域进行使用
dataFormat(input, pattern = "") { // 在参数列表中 通过 pattern="" 来指定形参默认值,防止报错
var dt = new Date(input);
// 获取年月日
var y = dt.getFullYear();
var m = (dt.getMonth() + 1).toString().padStart(2, '0');
var d = dt.getDate().toString().padStart(2, '0');
// 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日
// 否则,就返回 年-月-日 时:分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-${d}`;
} else {
// 获取时分秒
var hh = dt.getHours().toString().padStart(2, '0');
var mm = dt.getMinutes().toString().padStart(2, '0');
var ss = dt.getSeconds().toString().padStart(2, '0');
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
}
}
}
使用ES6中的字符串新方法 String.prototype.padStart(maxLength, fillString=’’) 或 String.prototype.padEnd(maxLength, fillString=’’)来填充字符串;
全局过滤器
// 定义一个全局过滤器
Vue.filter('dataFormat', function (input, pattern = '') {
var dt = new Date(input);
// 获取年月日
var y = dt.getFullYear();
var m = (dt.getMonth() + 1).toString().padStart(2, '0');
var d = dt.getDate().toString().padStart(2, '0');
// 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日
// 否则,就返回 年-月-日 时:分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-${d}`;
} else {
// 获取时分秒
var hh = dt.getHours().toString().padStart(2, '0');
var mm = dt.getMinutes().toString().padStart(2, '0');
var ss = dt.getSeconds().toString().padStart(2, '0');
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
}
});
注意:当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,即:局部过滤器优先于全局过滤器被调用!
键盘修饰符以及自定义键盘修饰符
1.x中自定义键盘修饰符【了解即可】
Vue.directive('on').keyCodes.f2 = 113;
2.x中自定义键盘修饰符
- 通过
Vue.config.keyCodes.名称 = 按键值
来自定义案件修饰符的别名:
Vue.config.keyCodes.f2 = 113;
- 使用自定义的按键修饰符:
<input type="text" v-model="name" @keyup.f2="add">
自定义指令
- 自定义全局和局部的 自定义指令:
// 自定义全局指令 v-focus,为绑定的元素自动获取焦点:
Vue.directive('focus', {
inserted: function (el) { // inserted 表示被绑定元素插入父节点时调用
el.focus();
}
});
// 自定义局部指令 v-color 和 v-font-weight,为绑定的元素设置指定的字体颜色 和 字体粗细:
directives: {
color: { // 为元素设置指定的字体颜色
bind(el, binding) {
el.style.color = binding.value;
}
},
'font-weight': function (el, binding2) { // 自定义指令的简写形式,等同于定义了 bind 和 update 两个钩子函数
el.style.fontWeight = binding2.value;
}
}
- 自定义指令的使用方式:
<input type="text" v-model="searchName" v-focus v-color="'red'" v-font-weight="900">
Vue 1.x 中 自定义元素指令【已废弃,了解即可】
Vue.elementDirective('red-color', {
bind: function () {
this.el.style.color = 'red';
}
});
使用方式:
<red-color>1232</red-color>
vue实例的生命周期
- 什么是生命周期:从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期!
- 生命周期钩子:就是生命周期事件的别名而已;
- 生命周期钩子 = 生命周期函数 = 生命周期事件
- 主要的生命周期函数分类:
- 创建期间的生命周期函数:
- beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
- created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板
- beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
- mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示
- 运行期间的生命周期函数:
- beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
- updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
- 销毁期间的生命周期函数:
- beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
- destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
vue-resource 实现 get, post, jsonp请求
除了 vue-resource 之外,还可以使用 axios
的第三方包实现实现数据的请求
- 之前的学习中,如何发起数据请求?
- 常见的数据请求类型? get post jsonp
- 测试的URL请求资源地址:
- get请求地址: http://vue.studyit.io/api/getlunbo
- post请求地址:http://vue.studyit.io/api/post
- jsonp请求地址:http://vue.studyit.io/api/jsonp
- JSONP的实现原理
- 由于浏览器的安全性限制,不允许AJAX访问 协议不同、域名不同、端口号不同的 数据接口,浏览器认为这种访问不安全;
- 可以通过动态创建script标签的形式,把script标签的src属性,指向数据接口的地址,因为script标签不存在跨域限制,这种数据获取方式,称作JSONP(注意:根据JSONP的实现原理,知晓,JSONP只支持Get请求);
- 具体实现过程:
- 先在客户端定义一个回调方法,预定义对数据的操作;
- 再把这个回调方法的名称,通过URL传参的形式,提交到服务器的数据接口;
- 服务器数据接口组织好要发送给客户端的数据,再拿着客户端传递过来的回调方法名称,拼接出一个调用这个方法的字符串,发送给客户端去解析执行;
- 客户端拿到服务器返回的字符串之后,当作Script脚本去解析执行,这样就能够拿到JSONP的数据了;
- 带大家通过 Node.js ,来手动实现一个JSONP的请求例子;
const http = require('http');
// 导入解析 URL 地址的核心模块
const urlModule = require('url');
const server = http.createServer();
// 监听 服务器的 request 请求事件,处理每个请求
server.on('request', (req, res) => {
const url = req.url;
// 解析客户端请求的URL地址
var info = urlModule.parse(url, true);
// 如果请求的 URL 地址是 /getjsonp ,则表示要获取JSONP类型的数据
if (info.pathname === '/getjsonp') {
// 获取客户端指定的回调函数的名称
var cbName = info.query.callback;
// 手动拼接要返回给客户端的数据对象
var data = {
name: 'zs',
age: 22,
gender: '男',
hobby: ['吃饭', '睡觉', '运动']
}
// 拼接出一个方法的调用,在调用这个方法的时候,把要发送给客户端的数据,序列化为字符串,作为参数传递给这个调用的方法:
var result = `${cbName}(${JSON.stringify(data)})`;
// 将拼接好的方法的调用,返回给客户端去解析执行
res.end(result);
} else {
res.end('404');
}
});
server.listen(3000, () => {
console.log('server running at http://127.0.0.1:3000');
});
- vue-resource 的配置步骤:
- 直接在页面中,通过
script
标签,引入vue-resource
的脚本文件; - 注意:引用的先后顺序是:先引用
Vue
的脚本文件,再引用vue-resource
的脚本文件;
- 发送get请求:
getInfo() { // get 方式获取数据
this.$http.get('http://127.0.0.1:8899/api/getlunbo').then(res => {
console.log(res.body);
})
}
- 发送post请求:
postInfo() {
var url = 'http://127.0.0.1:8899/api/post';
// post 方法接收三个参数:
// 参数1: 要请求的URL地址
// 参数2: 要发送的数据对象
// 参数3: 指定post提交的编码类型为 application/x-www-form-urlencoded
this.$http.post(url, { name: 'zs' }, { emulateJSON: true }).then(res => {
console.log(res.body);
});
}
- 发送JSONP请求获取数据:
jsonpInfo() { // JSONP形式从服务器获取数据
var url = 'http://127.0.0.1:8899/api/jsonp';
this.$http.jsonp(url).then(res => {
console.log(res.body);
});
}
配置本地数据库和数据接口API
- 先解压安装
PHPStudy
; - 解压安装
Navicat
这个数据库可视化工具,并激活; - 打开
Navicat
工具,新建空白数据库,名为dtcmsdb4
; - 双击新建的数据库,连接上这个空白数据库,在新建的数据库上
右键
->运行SQL文件
,选择并执行dtcmsdb4.sql
这个数据库脚本文件;如果执行不报错,则数据库导入完成; - 进入文件夹
vuecms3_nodejsapi
内部,执行npm i
安装所有的依赖项; - 先确保本机安装了
nodemon
, 没有安装,则运行npm i nodemon -g
进行全局安装,安装完毕后,进入到vuecms3_nodejsapi
目录 ->src
目录 -> 双击运行start.bat
- 如果API启动失败,请检查 PHPStudy 是否正常开启,同时,检查
app.js
中第14行
中数据库连接配置字符串是否正确;PHPStudy 中默认的 用户名是root,默认的密码也是root
品牌管理改造
展示品牌列表
添加品牌数据
删除品牌数据
Vue中的动画
为什么要有动画:动画能够提高用户的体验,帮助用户更好的理解页面中的功能;
使用过渡类名
- HTML结构:
<div id="app">
<input type="button" value="动起来" @click="myAnimate">
<!-- 使用 transition 将需要过渡的元素包裹起来 -->
<transition name="fade">
<div v-show="isshow">动画哦</div>
</transition>
</div>
- VM 实例:
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
isshow: false
},
methods: {
myAnimate() {
this.isshow = !this.isshow;
}
}
});
- 定义两组类样式:
/* 定义进入和离开时候的过渡状态 */
.fade-enter-active,
.fade-leave-active {
transition: all 0.2s ease;
position: absolute;
}
/* 定义进入过渡的开始状态 和 离开过渡的结束状态 */
.fade-enter,
.fade-leave-to {
opacity: 0;
transform: translateX(100px);
}
使用第三方 CSS 动画库
- 导入动画类库:
<link rel="stylesheet" type="text/css" href="./lib/animate.css">
- 定义 transition 及属性:
<transition
enter-active-class="fadeInRight"
leave-active-class="fadeOutRight"
:duration="{ enter: 500, leave: 800 }">
<div class="animated" v-show="isshow">动画哦</div>
</transition>
使用动画钩子函数
- 定义 transition 组件以及三个钩子函数:
<div id="app">
<input type="button" value="切换动画" @click="isshow = !isshow">
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter">
<div v-if="isshow" class="show">OK</div>
</transition>
</div>
- 定义三个 methods 钩子方法:
methods: {
beforeEnter(el) { // 动画进入之前的回调
el.style.transform = 'translateX(500px)';
},
enter(el, done) { // 动画进入完成时候的回调
el.offsetWidth;
el.style.transform = 'translateX(0px)';
done();
},
afterEnter(el) { // 动画进入完成之后的回调
this.isshow = !this.isshow;
}
}
- 定义动画过渡时长和样式:
.show{
transition: all 0.4s ease;
}
v-for 的列表过渡
- 定义过渡样式:
<style>
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateY(10px);
}
.list-enter-active,
.list-leave-active {
transition: all 0.3s ease;
}
</style>
- 定义DOM结构,其中,需要使用 transition-group 组件把v-for循环的列表包裹起来:
<div id="app">
<input type="text" v-model="txt" @keyup.enter="add">
<transition-group tag="ul" name="list">
<li v-for="(item, i) in list" :key="i">{{item}}</li>
</transition-group>
</div>
- 定义 VM中的结构:
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
txt: '',
list: [1, 2, 3, 4]
},
methods: {
add() {
this.list.push(this.txt);
this.txt = '';
}
}
});
列表的排序过渡
<transition-group>
组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的 v-move
特性,它会在元素的改变定位的过程中应用。
v-move
和v-leave-active
结合使用,能够让列表的过渡更加平缓柔和:
.v-move{
transition: all 0.8s ease;
}
.v-leave-active{
position: absolute;
}
vuex
const store = new vuex.store({
// state 通过 action 屌用 mutation,mutation 操作 state(devtool只监视mutation)
state:{a:5,b:12}, //初始状态 json
actions:{ //对mutation的封装
addA(context,n){ //context就是当前store对象 这个add随意定方法名,就是dispath来调用的方法名
context.commit('addA',n) //commit就是调用mutation里的方法(‘哪个方法’,传参数)
},
addB(context,n){ //context就是当前store对象 这个add随意定方法名,就是dispath来调用的方法名
context.commit('addB',n) //commit就是调用mutation里的方法(‘哪个方法’,传参数)
}
// 简写add({commit},n){commit('add',n)}
},
mutations:{ //操作state的
addA(state,n){ //state就是当前store的state
state.a+=n
},
addB(state,n){ //state就是当前store的state
state.b+=n
}
},
moudles:{
//对state做模块区分,加了这个读取state是一个json: {'device':{'a':'5','b':'12'},'user':{'a':'5','b':'12'}}
device, //设备相关js
user //用户相关js
},
getters:{ // 相当于computed ,当其中一个值变化,自动变化
count(state){
return state.a+state.b
}
}
})
// vuex 辅助工具
mapState //state 映射到 computed
mapActions //actions 映射到 methods
mapGetters //getters 映射到 computed
// vue组件修改
this.$store.dispatch('addA',5)
this.$store.getters.count
//getter还可以配合computed来用
//两个好处
//1.使用方便 {{count}} 相当于上面的使用
//computed可读可写
computed:{
count:{
get(){
return this.$store.getters.count;
},
set(value){
this.$store.dispatch('addA',value-5)
this.$store.dispatch('addB',5)
}
}
}
// 使用vuex辅助工具
import {mapState,mapAction,mapGetters} from 'vuex'
method:{
...maoActions(['addA','addB'])
},
computed:{
...mapState(['a','b']),
...maoGetters(['count'])
}
相关文章
- vue.js 1.x 文档
- vue.js 2.x 文档
- String.prototype.padStart(maxLength, fillString)
- js 里面的键盘事件对应的键码
- pagekit/vue-resource
- navicat如何导入sql文件和导出sql文件
- 贝塞尔在线生成器
1. 懒加载 和 预加载
就是利用div自定义属性携带图片路径,然后在需要显示图片时通过js把路径给到img
<div data-src="http://www.baidu.com/abc.jpg">
<img src="" />
</div>
通常用在加载首页和轮播图时有很多图片的情况
2. session 、cookie、 tokeyn
3. 模块化(AMD、CMD、CommonJS、ES6)
4. jsonp
原理:
//服务器
//客户端
<script type="text/javascript" src="http://127.0.0.1:3000/data?callback=回调函数名"></script>
面试
做过什么功能模块
有没有看过什么源代码
你在项目中中什么角色,要不要与后端交互
ES6新特性
有没有封装过插件
JQuery实例对象不是DOM对象,是一个伪数组
node.js有没有写过
webpack
vue双向数据绑定原理基于es5的set和get, 组件传值,vuex,product
其他前端相关技术点:
- PWA
- electron
- 同构nuxt.js
- next.js
- ssr
- react native
- flutter
版本
- vue2.0
- react15.0
- jquery
git
git廖雪峰
初始化一个Git仓库:git init [新建一个目录初始化]
添加文件到Git仓库:
添加到暂存区:git add file
提交到本地版本库:git commit -m <message>
工作区的状态:git status
查看修改过的内容:git diff
回退到上几个版本:git reset --hard HEAD^ 【如果多个用HEAD~10】
查看提交历史: git log
回退到指定历史版本:git reset --hard commit_id
查看命令历史:git reflog
查看工作区和版本库里面最新版本的区别:git diff HEAD -- <file>
把暂存区的修改回退到工作区:git reset HEAD <file>
用版本库里的版本替换工作区的版本:git checkout -- file 【工作区是修改还是删除一键还原】
删除版本库文件:git rm file
关联一个远程仓库:git remote add origin 地址 【origin相当于给地址定义一个名字】
本地库的内容推送到远程:git push -u origin master 【-u第一次推送加上可以把本地分支和远程分支关联起来】
克隆一个仓库:git clone 地址
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
看到分支合并图:git log --graph
把当前工作现场“储藏”起来:git stash
普通方式合并并提交:git merge --no-ff -m "merged bug fix 101" issue-101 【有合并历史记录】
查看存储了哪些工作区文件:git stash list
把存储区内容恢复到工作区:
1)git stash apply 【恢复后,stash内容并不删除,你需要用git stash drop来删除;】
2)git stash pop 恢复的同时把stash内容也删了
3)git stash apply stash@{0} 恢复指定的stash
强行删除一个没有被合并过的分支:git branch -D <name>
eslint常见配置规格
"no-alert": 0,//禁止使用alert confirm prompt
"no-array-constructor": 2,//禁止使用数组构造器
"no-bitwise": 0,//禁止使用按位运算符
"no-caller": 1,//禁止使用arguments.caller或arguments.callee
"no-catch-shadow": 2,//禁止catch子句参数与外部作用域变量同名
"no-class-assign": 2,//禁止给类赋值
"no-cond-assign": 2,//禁止在条件表达式中使用赋值语句
"no-console": 2,//禁止使用console
"no-const-assign": 2,//禁止修改const声明的变量
"no-constant-condition": 2,//禁止在条件中使用常量表达式 if(true) if(1)
"no-continue": 0,//禁止使用continue
"no-control-regex": 2,//禁止在正则表达式中使用控制字符
"no-debugger": 2,//禁止使用debugger
"no-delete-var": 2,//不能对var声明的变量使用delete操作符
"no-div-regex": 1,//不能使用看起来像除法的正则表达式/=foo/
"no-dupe-keys": 2,//在创建对象字面量时不允许键重复 {a:1,a:1}
"no-dupe-args": 2,//函数参数不能重复
"no-duplicate-case": 2,//switch中的case标签不能重复
"no-else-return": 2,//如果if语句里面有return,后面不能跟else语句
"no-empty": 2,//块语句中的内容不能为空
"no-empty-character-class": 2,//正则表达式中的[]内容不能为空
"no-empty-label": 2,//禁止使用空label
"no-eq-null": 2,//禁止对null使用==或!=运算符
"no-eval": 1,//禁止使用eval
"no-ex-assign": 2,//禁止给catch语句中的异常参数赋值
"no-extend-native": 2,//禁止扩展native对象
"no-extra-bind": 2,//禁止不必要的函数绑定
"no-extra-boolean-cast": 2,//禁止不必要的bool转换
"no-extra-parens": 2,//禁止非必要的括号
"no-extra-semi": 2,//禁止多余的冒号
"no-fallthrough": 1,//禁止switch穿透
"no-floating-decimal": 2,//禁止省略浮点数中的0 .5 3.
"no-func-assign": 2,//禁止重复的函数声明
"no-implicit-coercion": 1,//禁止隐式转换
"no-implied-eval": 2,//禁止使用隐式eval
"no-inline-comments": 0,//禁止行内备注
"no-inner-declarations": [2, "functions"],//禁止在块语句中使用声明(变量或函数)
"no-invalid-regexp": 2,//禁止无效的正则表达式
"no-invalid-this": 2,//禁止无效的this,只能用在构造器,类,对象字面量
"no-irregular-whitespace": 2,//不能有不规则的空格
"no-iterator": 2,//禁止使用__iterator__ 属性
"no-label-var": 2,//label名不能与var声明的变量名相同
"no-labels": 2,//禁止标签声明
"no-lone-blocks": 2,//禁止不必要的嵌套块
"no-lonely-if": 2,//禁止else语句内只有if语句
"no-loop-func": 1,//禁止在循环中使用函数(如果没有引用外部变量不形成闭包就可以)
"no-mixed-requires": [0, false],//声明时不能混用声明类型
"no-mixed-spaces-and-tabs": [2, false],//禁止混用tab和空格
"linebreak-style": [0, "windows"],//换行风格
"no-multi-spaces": 1,//不能用多余的空格
"no-multi-str": 2,//字符串不能用\换行
"no-multiple-empty-lines": [1, {"max": 2}],//空行最多不能超过2行
"no-native-reassign": 2,//不能重写native对象
"no-negated-in-lhs": 2,//in 操作符的左边不能有!
"no-nested-ternary": 0,//禁止使用嵌套的三目运算
"no-new": 1,//禁止在使用new构造一个实例后不赋值
"no-new-func": 1,//禁止使用new Function
"no-new-object": 2,//禁止使用new Object()
"no-new-require": 2,//禁止使用new require
"no-new-wrappers": 2,//禁止使用new创建包装实例,new String new Boolean new Number
"no-obj-calls": 2,//不能调用内置的全局对象,比如Math() JSON()
"no-octal": 2,//禁止使用八进制数字
"no-octal-escape": 2,//禁止使用八进制转义序列
"no-param-reassign": 2,//禁止给参数重新赋值
"no-path-concat": 0,//node中不能使用__dirname或__filename做路径拼接
"no-plusplus": 0,//禁止使用++,--
"no-process-env": 0,//禁止使用process.env
"no-process-exit": 0,//禁止使用process.exit()
"no-proto": 2,//禁止使用__proto__属性
"no-redeclare": 2,//禁止重复声明变量
"no-regex-spaces": 2,//禁止在正则表达式字面量中使用多个空格 /foo bar/
"no-restricted-modules": 0,//如果禁用了指定模块,使用就会报错
"no-return-assign": 1,//return 语句中不能有赋值表达式
"no-script-url": 0,//禁止使用javascript:void(0)
"no-self-compare": 2,//不能比较自身
"no-sequences": 0,//禁止使用逗号运算符
"no-shadow": 2,//外部作用域中的变量不能与它所包含的作用域中的变量或参数同名
"no-shadow-restricted-names": 2,//严格模式中规定的限制标识符不能作为声明时的变量名使用
"no-spaced-func": 2,//函数调用时 函数名与()之间不能有空格
"no-sparse-arrays": 2,//禁止稀疏数组, [1,,2]
"no-sync": 0,//nodejs 禁止同步方法
"no-ternary": 0,//禁止使用三目运算符
"no-trailing-spaces": 1,//一行结束后面不要有空格
"no-this-before-super": 0,//在调用super()之前不能使用this或super
"no-throw-literal": 2,//禁止抛出字面量错误 throw "error";
"no-undef": 1,//不能有未定义的变量
"no-undef-init": 2,//变量初始化时不能直接给它赋值为undefined
"no-undefined": 2,//不能使用undefined
"no-unexpected-multiline": 2,//避免多行表达式
"no-underscore-dangle": 1,//标识符不能以_开头或结尾
"no-unneeded-ternary": 2,//禁止不必要的嵌套 var isYes = answer === 1 ? true : false;
"no-unreachable": 2,//不能有无法执行的代码
"no-unused-expressions": 2,//禁止无用的表达式
"no-unused-vars": [2, {"vars": "all", "args": "after-used"}],//不能有声明后未被使用的变量或参数
"no-use-before-define": 2,//未定义前不能使用
"no-useless-call": 2,//禁止不必要的call和apply
"no-void": 2,//禁用void操作符
"no-var": 0,//禁用var,用let和const代替
"no-warning-comments": [1, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],//不能有警告备注
"no-with": 2,//禁用with
"array-bracket-spacing": [2, "never"],//是否允许非空数组里面有多余的空格
"arrow-parens": 0,//箭头函数用小括号括起来
"arrow-spacing": 0,//=>的前/后括号
"accessor-pairs": 0,//在对象中使用getter/setter
"block-scoped-var": 0,//块语句中使用var
"brace-style": [1, "1tbs"],//大括号风格
"callback-return": 1,//避免多次调用回调什么的
"camelcase": 2,//强制驼峰法命名
"comma-dangle": [2, "never"],//对象字面量项尾不能有逗号
"comma-spacing": 0,//逗号前后的空格
"comma-style": [2, "last"],//逗号风格,换行时在行首还是行尾
"complexity": [0, 11],//循环复杂度
"computed-property-spacing": [0, "never"],//是否允许计算后的键名什么的
"consistent-return": 0,//return 后面是否允许省略
"consistent-this": [2, "that"],//this别名
"constructor-super": 0,//非派生类不能调用super,派生类必须调用super
"curly": [2, "all"],//必须使用 if(){} 中的{}
"default-case": 2,//switch语句最后必须有default
"dot-location": 0,//对象访问符的位置,换行的时候在行首还是行尾
"dot-notation": [0, { "allowKeywords": true }],//避免不必要的方括号
"eol-last": 0,//文件以单一的换行符结束
"eqeqeq": 2,//必须使用全等
"func-names": 0,//函数表达式必须有名字
"func-style": [0, "declaration"],//函数风格,规定只能使用函数声明/函数表达式
"generator-star-spacing": 0,//生成器函数*的前后空格
"guard-for-in": 0,//for in循环要用if语句过滤
"handle-callback-err": 0,//nodejs 处理错误
"id-length": 0,//变量名长度
"indent": [2, 4],//缩进风格
"init-declarations": 0,//声明时必须赋初值
"key-spacing": [0, { "beforeColon": false, "afterColon": true }],//对象字面量中冒号的前后空格
"lines-around-comment": 0,//行前/行后备注
"max-depth": [0, 4],//嵌套块深度
"max-len": [0, 80, 4],//字符串最大长度
"max-nested-callbacks": [0, 2],//回调嵌套深度
"max-params": [0, 3],//函数最多只能有3个参数
"max-statements": [0, 10],//函数内最多有几个声明
"new-cap": 2,//函数名首行大写必须使用new方式调用,首行小写必须用不带new方式调用
"new-parens": 2,//new时必须加小括号
"newline-after-var": 2,//变量声明后是否需要空一行
"object-curly-spacing": [0, "never"],//大括号内是否允许不必要的空格
"object-shorthand": 0,//强制对象字面量缩写语法
"one-var": 1,//连续声明
"operator-assignment": [0, "always"],//赋值运算符 += -=什么的
"operator-linebreak": [2, "after"],//换行时运算符在行尾还是行首
"padded-blocks": 0,//块语句内行首行尾是否要空行
"prefer-const": 0,//首选const
"prefer-spread": 0,//首选展开运算
"prefer-reflect": 0,//首选Reflect的方法
"quotes": [1, "single"],//引号类型 `` "" ''
"quote-props":[2, "always"],//对象字面量中的属性名是否强制双引号
"radix": 2,//parseInt必须指定第二个参数
"id-match": 0,//命名检测
"require-yield": 0,//生成器函数必须有yield
"semi": [2, "always"],//语句强制分号结尾
"semi-spacing": [0, {"before": false, "after": true}],//分号前后空格
"sort-vars": 0,//变量声明时排序
"space-after-keywords": [0, "always"],//关键字后面是否要空一格
"space-before-blocks": [0, "always"],//不以新行开始的块{前面要不要有空格
"space-before-function-paren": [0, "always"],//函数定义时括号前面要不要有空格
"space-in-parens": [0, "never"],//小括号里面要不要有空格
"space-infix-ops": 0,//中缀操作符周围要不要有空格
"space-return-throw-case": 2,//return throw case后面要不要加空格
"space-unary-ops": [0, { "words": true, "nonwords": false }],//一元运算符的前/后要不要加空格
"spaced-comment": 0,//注释风格要不要有空格什么的
"strict": 2,//使用严格模式
"use-isnan": 2,//禁止比较时使用NaN,只能用isNaN()
"valid-jsdoc": 0,//jsdoc规则
"valid-typeof": 2,//必须使用合法的typeof的值
"vars-on-top": 2,//var必须放在作用域顶部
"wrap-iife": [2, "inside"],//立即执行函数表达式的小括号风格
"wrap-regex": 0,//正则表达式字面量用小括号包起来
"yoda": [2, "never"]//禁止尤达条件
正则表达式
https://wangdoc.com/javascript/stdlib/regexp.html
获取元素位置的一些属性方法总结
Element.getBoundingClientRect()方法返回元素的大小及其相对于视口的位置。
DOMRect 对象包含了一组用于描述边框的只读属性——left、top、right和bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的,也就是会随着滚动变化
- x\y:元素的左上角和父元素左上角的距离
- width/height:边框 + 内边距 + 内容框
- top:元素的上边界和父元素上边界的距离
- left:元素的左边界和父元素左边界的距离
- right:元素的右边界和父元素的左边界的距离
- bottom:元素的下边界和父元素上边界的距离
Element.clientWidth / element.clientHeight (内边距 + 内容框)
属性表示元素的内部宽度/高度,以像素计。该属性包括内边距,但不包括垂直/水平滚动条(如果有)、边框和外边距(只读)
element.offsetWidth / element.offsetHeight (边框 + 内边距 + 内容框)
返回一个元素的布局宽度。一个典型的(译者注:各浏览器的offsetWidth可能有所不同)offsetWidth是测量包含元素的边框(border)、水平/垂直内边距(padding)、垂直/水平滚动条(scrollbar)(如果存在的话)、以及CSS设置的宽度(width)/高度的值。
element.scrollWidth / element.scrollHeight
这个只读属性是元素内容宽度/高度的一种度量,包括由于overflow溢出而在屏幕上不可见的内容。
值等于元素在不使用水平/垂直滚动条的情况下适合视口中的所有内容所需的最小宽度/高度。
它还可以包括伪元素的宽度,例如::before或::after。
如果元素的内容可以适合而不需要水平滚动条,则其scrollWidth等于clientWidth
element.clientTop / element.clientLeft
上边框、左边框
element.offsetTop / element.offsetLeft
当前元素顶部距离最近父元素顶部/左边的距离(只读)
element.scrollTop / element.scrollLeft
这个元素的顶部/左边到视口可见内容(的顶部/左边)的距离的度量(元素被卷进去的高度和宽度)(可读可写)
window.innerHeight / window.innerWidth
浏览器窗口的视口(viewport)高度/宽度(以像素为单位);如果有水平/垂直滚动条,也包括滚动条高度/宽度。(只读)
Window.outerHeight / Window.outerWidth
获取整个浏览器窗口的高度/宽度(单位:像素),包括侧边栏(如果存在)、窗口镶边(window chrome)和窗口调正边框(window resizing borders/handles)(只读)
(window.scrollX/window.pageXOffset ) / (window.scrollY/window.pageYOffset )
返回文档/页面水平方向滚动的像素值(是一个浮点数)/返回文档在垂直方向已滚动的像素值(是一个浮点数)
window.screenX / window.screenY
返回浏览器左边界到操作系统桌面左边界的水平距离像素值。/返回浏览器顶部距离系统桌面顶部的垂直距离。
window.screen.width / window.screen.height
操作系统桌面(屏幕)的宽/高
window.screen.availWidth / window.screen.availHeight
操作系统桌面(屏幕)可用宽高(去除任务栏)
设置/获取文档滚动条距离的时候,DTD是否存在会影响document.body.scrollTop 与 document.documentElement.scrollTop的取值
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;