最强前端笔记(没有之一)(^-^)

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

 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.txtmove
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值">

特殊字符

	&nbsp 空格
	
	&lt   <
	
	&gt   >
	
	&copy ©️ 

列表

无序列表

<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;
}

屏幕适配

流式布局(百分比)

  1. width=100%;【任何设备网页宽度等于浏览器宽度】
  2. 任何设备内容不缩放
  • 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)

  1. display:flex; 设置父级盒子为伸缩盒子
  2. 当父级盒子为伸缩盒子时,子元素在父级中一行显示(沿主轴排列)
在伸缩盒子中有两条轴
主轴默认水平显示,侧轴垂直
flex-direction:row;(主轴默认值水平)
flex-direction:column;(主轴垂直显示)
flex-direction:row-reverse;(主轴水平反向)
flex-direction:column-reverse;(主轴垂直反向)
  1. 子元素在主轴的对齐方式
justify-content:flex-statr;(默认)
justify-content:flex-end;(右侧对齐)
justify-content:center;
justify-content:space-between;(两端对齐)
justify-content:space-around;(四周留白分布对齐)
  1. 子元素在侧轴的对齐方式
align-items:flex-statr;
align-items:flex-end;
align-items:center;
align-itmes:baseline;(基线对齐)
align-itmes:stretch;(拉伸-默认)
  1. 设置元素是否换行显示(flew-wrap)
flex-wrap:warp;(默认nowarp)
  1. 设置元素换行后相对侧轴的对齐方式
align-content:stretch(默认);
align-content:flex-statr;
align-content:flex-end;
align-content:center;
align-content:space-between;
align-content:space-around;
  1. flex:1;设置元素在父元素中占的比例;
  2. order:1;元素排序
  3. 设置元素自身对齐方式
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 的框架
    
  • 下载
    1. 点击链接下载

      生产环境版本:  代码已经被压缩过,可以直接放到服务器上部署.
      
      源代码版本: 代码没有经过压缩,用户可以修改源代码
      
    2. 通过link标签可以引用

      <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
      
    3. 通过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>
    
  • 排版
    1. 标题
      ☞  可以直接使用  <h1></h1><h6></h6> 标签
      ☞  可以给标签设置  .h1  到  .h6  的类名表示标题
      
    2. 其他行内元素
      ☞ Bootstrap 支持所有HTML标签行内元素
      ☞ 例如:
      	<mark>让文本高亮显示</mark>  | <del> 删除线 </del>  |  <s></s>  
          <strong></strong> | <em> </em>  ...
      ☞ 新标签:
      	 <small>小号文本标签</small>  或者 .small类名可以实现相同效果
      
    3. 对齐方式
        .text-left : 文本左对齐
      .text-center:  文本居中对齐
       .text-right: 文本右对齐
      
    4. 改变字母大小写
      .text-lowercase: 将字母全部转换为小写
      .text-uppercase: 将字目全部转换为大写
      .text-capitalize: 将首字母转换为大写
      
    5. 列表
      ☞ 去掉列表的默认样式:  .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&mdash;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&mdash;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()转换。)
  • 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);
  1. 返回值:返回变量的值
    任何的数据类型都可以是返回值
    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

提供了一系列的与数学相关的属性或方法

  1. Math.PI 获取圆周率
  2. Math.pow(x.y); 求x的y次幂
  3. Math.round(x); 对x值进行四舍五入运算,返回一个整数
  4. Math.abs(x); 对x值进行取绝对值
  5. 求三角函数:x的单位是弧度制
  Math.sin(x);
  Math.cos(x);
  Math.tan(x);
  1. Math.max(1,2,3,4); 获取一组数字的最大值
  2. Math.ceil(x); 天花板函数 (遇小数进1制)
  3. Math.floor(x); 地板函数 (遇小数舍掉)
  4. 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【手指改变时的手指列表】(手指松开事件用这个属性)//这个会获取两个点,手指和屏幕刚接触和手指和屏幕刚离开
    • 获取手指位置
    e.touches[0].clientY
    
    手指对象的clientX/Y 【参照可视区域的水平/垂直像素距离】
    手指对象的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 //返回窗口的文档显示区的高度。

  1. window对象被 称为顶级对象全局对象
  2. 因为全局变量和全局函数本质上都是window对象的属性或方法。
  3. 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)

全局作用域

变量的生命周期:当程序关闭时,会被从内存中释放,变成垃圾数据

局部作用域

变量的生命周期:函数执行完就被释放了,变成垃圾数据

作用域链

内层作用域可以访问外层作用域中的变量,但是外层作用域无法访问内层中的变量

判断是否有闭包

  1. 子函数可以操作外层函数中的局部变量
  2. 全局作用域中可以操作子函数
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()

深拷贝

  1. lodash库:_.cloneDeep()
  2. jQuery库:$extend(true,obj1,obj2)
  3. 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 新增语法

  1. let 和 const
  2. 解构赋值
  3. 函数 (箭头函数)

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 解构赋值

  1. 数组的解构
  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 参数只能是最后一个参数

三. 内置对象的扩展

  1. Array 的扩展
  2. String 的扩展
  3. Number 的扩展
  4. 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 的使用步骤

    1. 安装Node.js

    2. 命令行中安装 babel

    3. 配置文件 .babelrc

    4. 运行

  • 安装 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官网

五. 扩展阅读

ES6 扩展阅读

服务端开发基础(node)

浏览器的执行过程

  1. 用户打开浏览器
  2. 地址栏输入我们需要访问的网站网址(URL
  3. 浏览器通过 DNS 服务器 获取即将访问的网站 IP 地址
  4. 浏览器发起一个对这个 IP地址的 请求
  5. 服务端监听指定的 端口 的服务器软件接收到这个请求,进行相应的处理
  6. 服务端将处理完的结果返回给客户端浏览器(响应
  7. 浏览器将服务端返回的结果呈现到界面上

配置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

  • 全局成员

    Global Objects

  • Node.js 为 JavaScript 提供的服务器级别的 API

    • 文件读写
    • 网络通信
    • http 服务器

浏览器中的 JavaScript

  • ECMAScript
  • BOM
  • DOM

模块系统

模块的通讯规则

导出模块 module.exports
导入模块 require

  • exportsmodule.exports 的区别
    • module.exports
      • 每个模块中都有一个 module 对象
      • module 对象中有一个 exports 对象,模块最终导出的是此对象
    • exports
      • Node.js 为了方便,同时在每一个模块中都提供了一个成员叫:exports
      • exports 指向了 module.exportsexports = module.exports

模块分类

在 Node 中对不模块的一个具体分类,一共就三种类别:

  • 核心模块
    • 由 Node 本身提供,具名的,例如 fs 文件操作模块、http 网络操作模块
  • 第三方模块
    • 由第三方提供,使用的时候我们需要通过 npm 进行下载然后才可以加载使用,例如: mimeart-templatemarked
    • 注意:不可能有第三方包的名字和核心模块的名字是一样的,否则会造成冲突
  • 用户模块(自己写的)
    • 我们在文件中写的代码很多的情况下不好编写和维护,所以我们可以考虑把文件中的代码拆分到多个文件中,那这些我们自己创建的文件就是用户模块
      注意:
  1. 执行该命令前,应该先切到项目文件夹,并且项目文件夹不能为中文。
  2. 对于第三方模块,我们都是 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 服务器通信的过程就和打电话的过程一样。
    1. a 和 b 打电话,a 先要有 b 的手机号码 (IP和端口)
    2. a 给 b 拨打电话
    3. b 的电话响起,b 判断自己是否有空接听电话
    4. b 如果有空,接电话,双方可以通信(建立好通信的链接)
    5. 通信的过程双方要使用同样的语言说话
    6. 说话结束挂掉电话
  • 浏览器和 Web 服务器通信
    1. 浏览器中输入 IP 和 端口
    2. 浏览器向服务器要求通信(想要建立通信的链接)
    3. 服务器判断是否有资源处理该浏览器的通信
    4. 如果服务器有资源处理,则建立一个通信的链接
    5. 链接建立好以后,浏览器向服务器发送 HTTP 请求,服务器处理请求,并返回 HTTP 响应
    6. 通信结束后,服务器关闭连接

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)
    
  • 响应体

    返回的主体内容,如果请求的是网页返回网页的内容,如果请求的是图片返回图片的内容

请求的方法

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...')
})

统一处理静态资源

  • 自己处理

    1. 在网页中给所有的外部链接 加一个标示 /public/
    2. 在node中,判断当前请求的路径,是否包含/public/
    3. 为了方便找到文件的路径,把css、images文件夹放到了 新建的public文件夹中
    4. 读取文件,返回响应
  • 使用第三方模块

    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}}
        
  • 使用模板引擎改造留言板案例

浏览器是如何请求服务器

  1. 用户在浏览器地址栏中输入网站域名
  2. 浏览器拿到该域名自动去请求 DNS服务器查询 用户输入的域名对应的 ip 地址
  3. 浏览器拿到 ip 地址之后,通过ip地址+端口号(HTTP默认80)和服务器建立连接(通过 三次握手 )
  4. 浏览器将用户输入的 url 地址通过 HTTP 协议包装成 请求报文 ,(服务器ip地址和端口号) 发送到服务器
  5. 当HTTP服务器接收到客户端浏览器发送过来的请求报文时候,按照 HTTP 协议将请求报文解析出来
  6. 然后服务器拿到请求报文中的请求信息(例如请求路径url),做相应的业务逻辑处理操作
  7. 当业务逻辑处理完毕之后,服务器将要发送给客户端的数据按照 HTTP 协议包装成 响应报文
  8. 然后服务器将响应报文数据发送给客户端浏览器
  9. 当浏览器接收到服务器发送给自己的响应报文数据的时候,浏览器根据 HTTP 协议将报文内容解析出来
  10. 浏览器拿到响应报文体中的数据开始 解析渲染html、css,执行 JavaScript
  11. 如果在解析的过程(从上到下)中,发现有外链的标签(link、css、img)
  12. 浏览器会自动对该标签指向的 路径地址 发起新的请求,同上。

Express

Express 介绍

起步

安装

参考文档: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);
});

留言板案例

发表留言
  1. 获取 post 过来的数据 - 配置body-parser

  2. 读取 db.json,把内容转换成js数组对象

  3. 构造留言对象,把对象添加到数组中

  4. 把留言数组转换成json字符串,写入db.json

  5. 提示并跳转

    // 配置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>');
        });
      });
    });
    
留言列表
  1. 安装 art-template,导入模块

  2. 配置模板

    {{ 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 }}
    
  3. 读取 db.json,把内容转换成js的数组对象

  4. 使用art-template渲染模板

  5. 把渲染的网页,发送给浏览器

    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
      1. 大版本.次要版本.小版本
      2. 小版本:当项目在进行了局部修改或 bug 修正时,修正版本号加 1
      3. 次要版本:当项目在原有的基础上增加了部分功能时,主版本号不变,子版本号加 1
      4. 大版本:当项目在进行了重大修改或局部修正累积较多,而导致项目整体发生全局变化时,主版本号加 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
  • 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 
      SELECT1,列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;
  • 库(插件):提供某一个小功能,对项目的侵入性较小,如果某个库无法完成某些需求,可以很容易切换到其它库实现需求。
    1. 从Jquery 切换到 Zepto
    1. 从 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指令

跑马灯效果

  1. HTML结构:

<div id="app">

    <p>{{info}}</p>

    <input type="button" value="开启" v-on:click="go">

    <input type="button" value="停止" v-on:click="stop">

  </div>

  1. 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

简易计算器案例

  1. 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>

  1. 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样式

  1. 数组
<h1 :class="['red', 'thin']">这是一个邪恶的H1</h1>
  1. 数组中使用三元表达式
<h1 :class="['red', 'thin', isactive?'active':'']">这是一个邪恶的H1</h1>
  1. 数组中嵌套对象
<h1 :class="['red', 'thin', {'active': isactive}]">这是一个邪恶的H1</h1>
  1. 直接使用对象
<h1 :class="{red:true, italic:true, active:true, thin:true}">这是一个邪恶的H1</h1>

使用内联样式

  1. 直接在元素上通过 :style 的形式,书写样式对象
<h1 :style="{color: 'red', 'font-size': '40px'}">这是一个善良的H1</h1>
  1. 将样式对象,定义到 data 中,并直接引用到 :style
  • 在data上定义样式:
data: {
        h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' }
}
  • 在元素中,通过属性绑定的形式,将样式对象应用到元素中:
<h1 :style="h1StyleObj">这是一个善良的H1</h1>
  1. :style 中通过数组,引用多个 data 上的样式对象
  • 在data上定义样式:
data: {
        h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' },
        h1StyleObj2: { fontStyle: 'italic' }
}
  • 在元素中,通过属性绑定的形式,将样式对象应用到元素中:
<h1 :style="[h1StyleObj, h1StyleObj2]">这是一个善良的H1</h1>

品牌管理案例

添加新品牌

删除品牌

根据条件筛选品牌

  1. 1.x 版本中的filterBy指令,在2.x中已经被废除:

filterBy - 指令


<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>

  1. 在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 devtools - 安装方式 - 推荐

过滤器

概念:Vue.js 允许你自定义过滤器,可被用作一些常见的文本格式化。过滤器可以用在两个地方:mustache 插值和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符指示;

私有过滤器

  1. HTML元素:

<td>{{item.ctime | dataFormat('yyyy-mm-dd')}}</td>

  1. 私有 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中自定义键盘修饰符

  1. 通过Vue.config.keyCodes.名称 = 按键值来自定义案件修饰符的别名:

Vue.config.keyCodes.f2 = 113;

  1. 使用自定义的按键修饰符:

<input type="text" v-model="name" @keyup.f2="add">

自定义指令

  1. 自定义全局和局部的 自定义指令:

    // 自定义全局指令 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;

        }

      }

  1. 自定义指令的使用方式:

<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>

相关文章

  1. vue.js 1.x 文档
  2. vue.js 2.x 文档
  3. String.prototype.padStart(maxLength, fillString)
  4. js 里面的键盘事件对应的键码
  5. Vue.js双向绑定的实现原理

Vue.js - Day2

品牌管理案例

添加新品牌

删除品牌

根据条件筛选品牌

  1. 1.x 版本中的filterBy指令,在2.x中已经被废除:

filterBy - 指令


<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>

  1. 在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 devtools - 安装方式 - 推荐

过滤器

概念:Vue.js 允许你自定义过滤器,可被用作一些常见的文本格式化。过滤器可以用在两个地方:mustache 插值和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符指示;

私有过滤器

  1. HTML元素:

<td>{{item.ctime | dataFormat('yyyy-mm-dd')}}</td>

  1. 私有 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中自定义键盘修饰符

  1. 通过Vue.config.keyCodes.名称 = 按键值来自定义案件修饰符的别名:

Vue.config.keyCodes.f2 = 113;

  1. 使用自定义的按键修饰符:

<input type="text" v-model="name" @keyup.f2="add">

自定义指令

  1. 自定义全局和局部的 自定义指令:

    // 自定义全局指令 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;

        }

      }

  1. 自定义指令的使用方式:

<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 的第三方包实现实现数据的请求

  1. 之前的学习中,如何发起数据请求?
  2. 常见的数据请求类型? get post jsonp
  3. 测试的URL请求资源地址:
  • get请求地址: http://vue.studyit.io/api/getlunbo
  • post请求地址:http://vue.studyit.io/api/post
  • jsonp请求地址:http://vue.studyit.io/api/jsonp
  1. 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');
   });
  1. vue-resource 的配置步骤:
  • 直接在页面中,通过script标签,引入 vue-resource 的脚本文件;
  • 注意:引用的先后顺序是:先引用 Vue 的脚本文件,再引用 vue-resource 的脚本文件;
  1. 发送get请求:
getInfo() { // get 方式获取数据
  this.$http.get('http://127.0.0.1:8899/api/getlunbo').then(res => {
    console.log(res.body);
  })
}
  1. 发送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);
  });
}
  1. 发送JSONP请求获取数据:
jsonpInfo() { // JSONP形式从服务器获取数据
  var url = 'http://127.0.0.1:8899/api/jsonp';
  this.$http.jsonp(url).then(res => {
    console.log(res.body);
  });
}

配置本地数据库和数据接口API

  1. 先解压安装 PHPStudy;
  2. 解压安装 Navicat 这个数据库可视化工具,并激活;
  3. 打开 Navicat 工具,新建空白数据库,名为 dtcmsdb4;
  4. 双击新建的数据库,连接上这个空白数据库,在新建的数据库上右键 -> 运行SQL文件,选择并执行 dtcmsdb4.sql 这个数据库脚本文件;如果执行不报错,则数据库导入完成;
  5. 进入文件夹 vuecms3_nodejsapi 内部,执行 npm i 安装所有的依赖项;
  6. 先确保本机安装了 nodemon, 没有安装,则运行 npm i nodemon -g 进行全局安装,安装完毕后,进入到 vuecms3_nodejsapi目录 -> src目录 -> 双击运行 start.bat
  7. 如果API启动失败,请检查 PHPStudy 是否正常开启,同时,检查 app.js 中第 14行 中数据库连接配置字符串是否正确;PHPStudy 中默认的 用户名是root,默认的密码也是root

品牌管理改造

展示品牌列表

添加品牌数据

删除品牌数据

Vue中的动画

为什么要有动画:动画能够提高用户的体验,帮助用户更好的理解页面中的功能;

使用过渡类名

  1. HTML结构:
<div id="app">
    <input type="button" value="动起来" @click="myAnimate">
    <!-- 使用 transition 将需要过渡的元素包裹起来 -->
    <transition name="fade">
      <div v-show="isshow">动画哦</div>
    </transition>
  </div>
  1. VM 实例:
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
  el: '#app',
  data: {
    isshow: false
  },
  methods: {
    myAnimate() {
      this.isshow = !this.isshow;
    }
  }
});
  1. 定义两组类样式:
/* 定义进入和离开时候的过渡状态 */
    .fade-enter-active,
    .fade-leave-active {
      transition: all 0.2s ease;
      position: absolute;
    }

    /* 定义进入过渡的开始状态 和 离开过渡的结束状态 */
    .fade-enter,
    .fade-leave-to {
      opacity: 0;
      transform: translateX(100px);
    }

使用第三方 CSS 动画库

  1. 导入动画类库:
<link rel="stylesheet" type="text/css" href="./lib/animate.css">
  1. 定义 transition 及属性:
<transition
	enter-active-class="fadeInRight"
    leave-active-class="fadeOutRight"
    :duration="{ enter: 500, leave: 800 }">
  	<div class="animated" v-show="isshow">动画哦</div>
</transition>

使用动画钩子函数

  1. 定义 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>
  1. 定义三个 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;
        }
      }
  1. 定义动画过渡时长和样式:
.show{
      transition: all 0.4s ease;
    }

v-for 的列表过渡

  1. 定义过渡样式:
<style>
    .list-enter,
    .list-leave-to {
      opacity: 0;
      transform: translateY(10px);
    }

    .list-enter-active,
    .list-leave-active {
      transition: all 0.3s ease;
    }
</style>
  1. 定义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>
  1. 定义 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-movev-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'])
  
 }

相关文章

  1. vue.js 1.x 文档
  2. vue.js 2.x 文档
  3. String.prototype.padStart(maxLength, fillString)
  4. js 里面的键盘事件对应的键码
  5. pagekit/vue-resource
  6. navicat如何导入sql文件和导出sql文件
  7. 贝塞尔在线生成器

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;

screen

对于问题"handler: Invalid Object: LngLat(NaN, NaN)"的解决方法,可以采取以下几个步骤: 1. 查看center和position数据类型是否正确。确保center是一个非空的数组,且类型为[number, number]。可以通过console.log或者debugger来验证center的值和类型是否正确。 2. 检查地图容器是否设置了正确的宽度和高度。确保div容器的宽度和高度样式已经正确设置,以确保地图可以正确显示。例如,可以通过设置样式类或通过直接设置div元素的style属性来设置宽度和高度。 3. 检查相关赋值的地方,看是否有地方导致了center和marker.position的值为空数组[]。可以仔细检查代码中对center和marker.position赋值的逻辑,确保它们被正确地赋值为非空数组。 综上所述,解决"handler: Invalid Object: LngLat(NaN, NaN)"的方法包括检查center和position的数据类型、确保地图容器设置了正确的宽度和高度,以及检查相关赋值的地方是否导致了center和marker.position的值为空数组。通过逐一排查这些可能的问题,可以解决该错误。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [高德地图 vue-amap LngLat(NaN, NaN) 报错](https://blog.csdn.net/github_33538490/article/details/114028878)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [高德地图 react-amap LngLat(NaN, NaN) 报错](https://blog.csdn.net/czq_2020/article/details/129795912)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值