前端开发基础知识汇总

一.HTML

1.前言与常用标签

浏览器内核备注
IETridentIE、猎豹安全、360极速浏览器、百度浏览器
firefoxGecko可惜这几年已经没落了,打开速度慢、升级频繁、猪一样的队友flash、神一样的对手chrome。
Safariwebkit现在很多人错误地把 webkit 叫做 chrome内核(即使 chrome内核已经是 blink 了)。苹果感觉像被别人抢了媳妇,都哭晕再厕所里面了。
chromeChromium/Blink在 Chromium 项目中研发 Blink 渲染引擎(即浏览器核心),内置于 Chrome 浏览器之中。Blink 其实是 WebKit 的分支。大部分国产浏览器最新版都采用Blink内核。二次开发
Operablink现在跟随chrome用blink内核。

Web标准构成:主要包括结构(Structure)、表现(Presentation)和行为(Behavior)三个方面。

web标准小结

  • web标准有三层结构,分别是结构(html)、表现(css)和行为(javascript)
  • 结构类似人的身体, 表现类似人的着装, 行为类似人的行为动作
  • 理想状态下,他们三层都是独立的, 放到不同的文件里面
声明位于文档中的最前面的位置,处于 标签之前。此标签可告知浏览器文档使用哪种 HTML 或 XHTML 规范。 指定html 语言种类

head 头部. 标题 title 文档标题

标签名定义说明
标题标签作为标题使用,并且依据重要性递减

段落标签可以把 HTML 文档分割为若干段落

水平线标签没啥可说的,就是一条线

换行标签
div标签用来布局的,但是现在一行只能放一个div
span标签用来布局的,一行上可以放好多个span
标签显示效果
b或strong粗体
i或em斜体
s或del加删除线
u或ins加下划线

b 只是加粗 strong 除了可以加粗还有 强调的意思, 语义更强烈。

属性属性值描述
srcURL图像的路径
alt文本图像不能显示时的替换文本
title文本鼠标悬停时显示的内容
width像素设置图像的宽度
height像素设置图像的宽度
border数字设置图像边框的宽度

**注意: **

  1. 标签可以拥有多个属性,必须写在开始标签中,位于标签名后面。

  2. 属性之间不分先后顺序,标签名与属性、属性与属性之间均以空格分开。

  3. 采取 键值对 的格式 key=“value” 的格式

链接标签

<a href="跳转的路径">文字或图片</a>
属性作用
href用于指定链接目标的url地址,(必须属性)当为标签应用href属性时,它就具有了超链接的功能
target用于指定链接页面的打开方式,其取值有_self和_blank两种,其中_self为默认值,__blank为在新窗口中打开方式。
快捷键是: ctrl + / 或者 ctrl +shift + /

相对路径

路径分类符号
同一级路径
下一级路径“/”
上一级路径“…/”

锚点定位

  1. 使用相应的id名标注跳转目标的位置。 (找目标)

第2集

2. 使用 链接文本创建链接文本(被点击的) (拉关系) 我也有一个姓毕的姥爷..

base标签

  1. base 可以设置整体链接的打开状态
  2. base 写到 之间
  3. 把所有的连接 都默认添加 target="_blank" 在新窗口中打开链接

预格式化文本pre

 标签可定义预格式化的文本。被包围在 
 标签 元素中的文本通常会保留空格和换行符。而文本也会呈现为等宽字体。

特殊字符

大于号 &gt

小于号 &lt

空格 &nbsp

2.表格table

表格作用:

存在即是合理的。 表格的现在还是较为常用的一种标签,但不是用来布局,常见显示、展示表

格式数据

  1. table用于定义一个表格标签。
  2. tr标签 用于定义表格中的行,必须嵌套在 table标签中。
  3. td 用于定义表格中的单元格,必须嵌套在标签中。

**总结: **

  • 表格的主要目的是用来显示特殊数据的

  • 一个完整的表格有表格标签(table),行标签(tr),单元格标签(td)组成,没有列的标签

  • 中只能嵌套 类的单元格
  • 标签,他就像一个容器,可以容纳所有的元素

表格属性 重点记住 cellspacing 、 cellpadding

属性名含义常用属性值
border设置表格的边框(border="0"为无边框)像素值
cellspacing设置单元格与单元格边框之间的空白间距像素值(默认为2像素)
cellpadding设置单元格内容与单元格边框之间的空白间距像素值(默认为1像素)
width设置表格宽度像素值
height设置表格高度像素值
align这是表格在网页中的水平对齐方式left、center、right

表头单元格标签th

  • 作用:
    • 一般表头单元格位于表格的第一行或第一列,并且文本加粗居中
  • 语法:
    • 只需用表头标签<th></th>替代相应的单元格标签<td></td>即可

表格标题caption

  1. caption 元素定义表格标题,通常这个标题会被居中且显示于表格之上。
  2. caption 标签必须紧随 table 标签之后。
  3. 这个标签只存在 表格里面才有意义。

合并单元格

  • 跨行合并:rowspan=“合并单元格的个数”
  • 跨列合并:colspan=“合并单元格的个数”

合并的顺序我们按照 先上 后下 先左 后右 的顺序

  1. 先确定是跨行还是跨列合并
  2. 根据 先上 后下 先左 后右的原则找到目标单元格 然后写上 合并方式 还有 要合并的单元格数量 比如 :
  3. 删除多余的单元格 单元格

3.列表和表单

列表

无序列表ul

1. <ul></ul>中只能嵌套<li></li>,直接在<ul></ul>标签中输入其他标签或者文字的做法是不被允许的。
2. <li>与</li>之间相当于一个容器,可以容纳所有元素。

有序列表ol

  1. 列表项1
  2. 列表项2
  3. 列表项3
  4. ......

自定义列表

名词1
名词1解释1
名词1解释2
... 名词2
名词2解释1
名词2解释2
...
标签名定义说明
    无序标签里面只能包含li 没有顺序,我们以后布局中最常用的列表
      有序标签里面只能包含li 有顺序, 使用情况较少
      自定义列表里面有2个兄弟, dt 和 dd

      表单

      input控件

      • input 输入的意思
      • <input />标签为单标签
      • type属性设置不同的属性值用来指定不同的控件类型
      • 除了type属性还有别的属性
      type的属性描述
      text文本框
      password密码框
      radio单选按钮
      checkbox复选框
      button普通按钮
      submit提交按钮
      reset重置按钮
      image图像形式提交按钮
      file文件域
      属性属性值描述
      name由用户自定义控件的名称
      value由用户自定义input控件中的默认文本值
      size正整数input控件在页面中的显示宽度
      checkedchecked定义选择控件默认被选中的项
      maxlength正整数控件允许输入的最多字符数

      checked="checked"表示就默认选中了

      label标签

      作用: 用于绑定一个表单元素, 当点击label标签的时候, 被绑定的表单元素就会获得输入焦点。

      1.第一种用法就是用label直接包括input表单。

      2.第二种用法 for 属性规定 label 与哪个表单元素绑定


      textarea文本域

      • 语法:
      <textarea >
        文本内容
      </textarea>
      
      • 作用:

        通过textarea控件可以轻松地创建多行文本输入框.

        cols=“每行中的字符数” rows=“显示的行数” 我们实际开发不用

      select下拉列表

      选项1 选项2 选项3 ...
      1. <select> 中至少包含一对 option
      2. 在option 中定义selected =" selected "时,当前项即为默认选中项。

      form表单域

      各种表单控件
      属性属性值作用
      actionurl地址用于指定接收并处理表单数据的服务器程序的url地址。
      methodget/post用于设置表单数据的提交方式,其取值为get或post。
      name名称用于指定表单的名称,以区分同一个页面中的多个表单。

      二.CSS

      1.样式、选择器、文字文本样式

      行内样式

      <标签名 style=“属性1:属性值1; 属性2:属性值2; 属性3:属性值3;”> 内容 </标签名>

      内部样式

      外部样式

      属性作用
      rel定义当前文档与被链接文档之间的关系,在这里需要指定为“stylesheet”,表示被链接的文档是一个样式表文件。
      type定义所链接文档的类型,在这里需要指定为“text/CSS”,表示链接的外部文件为CSS样式表。我们都可以省略
      href定义所链接外部样式表文件的URL,可以是相对路径,也可以是绝对路径。

      选择器 CSS选择器干啥的? 选择标签用的, 把我们想要的标签选择出来

      选择器作用缺点使用情况用法
      标签选择器可以选出所有相同的标签,比如p不能差异化选择较多p { color:red;}
      类选择器可以选出1个或者多个标签可以根据需求选择非常多.nav { color: red; }
      id选择器一次只能选择器1个标签只能使用一次不推荐使用#nav {color: red;}
      通配符选择器选择所有的标签选择的太多,有部分不需要不推荐使用* {color: red;}

      文字文本样式font

      属性表示注意点
      font-size字号我们通常用的单位是px 像素,一定要跟上单位,谷歌浏览器默认的文字大小为16px,最小为12px
      font-family字体实际工作中按照团队约定来写字体 p{font-family: Arial,“Microsoft Yahei”, “微软雅黑”;}
      font-weight字体粗细记住加粗是 700 或者 bold , 不加粗 是 normal 或者 400 记住数字不要跟单位 数值在100-900之间
      font-style字体样式记住倾斜是 italic 不倾斜 是 normal 工作中我们最常用 normal
      font字体连写1. 字体连写是有顺序的 不能随意换位置 2. 其中字号 和 字体 必须同时出现 写法: 选择器 { font: font-style font-weight font-size/line-height font-family;}必须有font-size和font-family属性

      css外观属性

      属性表示注意点
      color颜色我们通常用 十六进制 比如 而且是简写形式 #fff
      line-height行高控制行与行之间的距离
      text-align水平对齐可以设定文字水平的对齐方式 left左对齐(默认);right右对齐;center居中对齐
      text-indent首行缩进通常我们用于段落首行缩进2个字的距离 text-indent: 2em; 1em 就是一个字的宽度 如果是汉字的段落, 1em 就是一个汉字的宽度
      text-decoration文本修饰记住 添加 下划线 underline ; 取消下划线 none;

      复合选择器

      选择器作用特征使用情况隔开符号及用法
      后代选择器用来选择元素后代是选择所有的子孙后代较多符号是空格 .nav a
      子代选择器选择 最近一级元素只选亲儿子较少符号是**>** .nav>p
      交集选择器选择两个标签交集的部分既是 又是较少没有符号 p.one
      并集选择器选择某些相同样式的选择器可以用于集体声明较多符号是逗号 .nav, .header
      链接伪类选择器给链接更改状态较多重点记住 a{} 和 a:hover 实际开发的写法

      伪类选择器

      • a:link /* 未访问的链接 */
      • a:visited /* 已访问的链接 */
      • a:hover /* 鼠标移动到链接上 */
      • a:active /* 选定的链接 */

      2.display、行高、背景、特性

      标签显示模式display

      元素模式元素排列设置样式默认宽度包含
      块级元素block一行只能放一个块级元素可以设置宽度高度容器的100%容器级可以包含任何标签
      行内元素inline一行可以放多个行内元素不可以直接设置宽度高度它本身内容的宽度容纳文本或则其他行内元素
      行内块元素inline-block一行放多个行内块元素可以设置宽度和高度它本身内容的宽度
      • 块转行内:display:inline;
      • 行内转块:display:block;
      • 块、行内元素转换为行内块: display: inline-block;

      行高line-height

      • 如果 行高 等 高度 文字会 垂直居中
      • 如果行高 大于 高度 文字会 偏下
      • 如果行高小于高度 文字会 偏上

      CSS 背景(background)

      属性作用
      background-color背景颜色预定义的颜色值/十六进制/RGB代码 语法:background-color:颜色值; 默认的值是 transparent 透明的
      background-image背景图片url(图片路径), none(无背景图,默认的) background-image : none | url (url)
      background-repeat是否平铺repeat 背景图像在纵向和横向上平铺(默认的) /no-repeat 不平铺 /repeat-x 在横向上平铺/repeat-y 在纵向平铺
      background-position背景位置length(百分比,长度值)/position(方位名词 : top | center | bottom | left | center | right) 分别是x 和 y坐标, 切记 如果有 精确数值单位,则必须按照先X 后Y 的写法
      background-attachment背景固定还是滚动scroll(随对象内容滚动) / fixed(背景图像固定)
      背景简写更简单background: 背景颜色 背景图片地址 背景平铺 背景滚动 背景位置; 他们没有顺序
      背景透明让盒子半透明background: rgba(0,0,0,0.3); 后面必须是 4个值,最后一个参数是alpha 透明度 取值范围 0~1之间,低于 ie9 的版本是不支持的

      CSS层叠性

      • 样式冲突,遵循的原则是就近原则。 那个样式离着结构近,就执行那个样式。
      • 样式不冲突,不会层叠

      CSS继承性

      子标签会继承父标签的某些样式,如文本颜色和字号。

      想要设置一个可继承的属性,只需将它应用于父元素即可。

      CSS优先级 权重

      标签选择器计算权重公式
      继承或者 *0,0,0,0
      每个元素(标签选择器)0,0,0,1
      每个类,伪类0,0,1,0
      每个ID0,1,0,0
      每个行内样式 style=""1,0,0,0
      每个!important 重要的∞ 无穷大

      数位之间没有进制 比如说: 0,0,0,5 + 0,0,0,5 =0,0,0,10 而不是 0,0, 1, 0, 所以不会存在10个div能赶上一个类选择器的情况。

      3.盒子模型

      • 盒子模型有元素的内容、边框(border)、内边距(padding)、和外边距(margin)组成。
      • 盒子里面的文字和图片等元素是 内容区域
      • 盒子的厚度 我们成为 盒子的边框
      • 盒子内容与边框的距离是内边距(类似单元格的 cellpadding)
      • 盒子与盒子之间的距离是外边距(类似单元格的 cellspacing)

      盒子边框border

      属性作用
      border-width定义边框粗细,单位是px
      border-style边框的样式
      border-color边框颜色

      边框的样式:

      • none:没有边框即忽略所有边框的宽度(默认值)
      • solid:边框为单实线(最为常用的)
      • dashed:边框为虚线
      • dotted:边框为点线

      综合写法border : border-width || border-style || border-color

      ​ border: 1px solid red; 没有顺序

      表格的细线边框border-collapse:collapse

      • 通过表格的cellspacing="0",将单元格与单元格之间的距离设置为0,

      • 但是两个单元格之间的边框会出现重叠,从而使边框变粗

      • 通过css属性:

        table{ border-collapse:collapse; }  
        
        • collapse 单词是合并的意思
        • border-collapse:collapse; 表示相邻边框合并在一起。

      内边距padding

      1. 添加了内边距,内容和边框 有了距离。
      2. 盒子会变大了(解决办法:通过给设置了宽高的盒子,减去相应的内边距的值,维持盒子原有的大小)
      值的个数表达意思
      1个值padding:上下左右内边距;
      2个值padding: 上下内边距 左右内边距 ;
      3个值padding:上内边距 左右内边距 下内边距;
      4个值padding: 上内边距 右内边距 下内边距 左内边距 ;

      盒子的实际的大小 = 内容的宽度和高度 + 内边距 + 边框

      如果没有给一个盒子指定宽度, 此时,如果给这个盒子指定padding, 则不会撑开盒子。

      外边距(margin)

      margin属性用于设置外边距。 margin就是控制盒子和盒子之间的距离,和padding类似。

      margin可以让一个块级盒子实现水平居中必须:

      • 盒子必须指定了宽度(width)
      • 然后就给左右的外边距都设置为auto,语法: margin:auto;或margin: 0 auto;

      清除元素的默认内外边距

      {
      padding:0; /
      清除内边距 /
      margin:0; /
      清除外边距 */
      }

      外边距合并

      1.相邻块元素垂直外边距的合并

      • 当上下相邻的两个块元素相遇时,如果上面的元素有下外边距margin-bottom
      • 下面的元素有上外边距margin-top,则他们之间的垂直间距不是margin-bottom与margin-top之和
      • 取两个值中的较大者这种现象被称为相邻块元素垂直外边距的合并(也称外边距塌陷)。

      2.嵌套块元素垂直外边距的合并(塌陷)

      • 对于两个嵌套关系的块元素,如果父元素没有上内边距及边框
      • 父元素的上外边距会与子元素的上外边距发生合并
      • 合并后的外边距为两者中的较大者

      解决方案:

      1. 可以为父元素定义上边框。
      2. 可以为父元素定义上内边距
      3. 可以为父元素添加overflow:hidden。
      4. 还有其他方法,比如浮动、固定、绝对定位的盒子不会有问题。

      圆角边框border-radius(CSS3)

      语法:border-radius:length; 让正方形length=50%则为圆形 , 对于长方形设置为高度的一半

      盒子阴影box-shadow(CSS3)

      box-shadow:水平阴影 垂直阴影 模糊距离(虚实) 阴影尺寸(影子大小) 阴影颜色 内/外阴影;

      4.浮动、书写顺序

      CSS 提供了 3 种机制来设置盒子的摆放位置,分别是

      普通流(标准流:块级元素,行内元素,行内块元素)

      浮动 (让盒子从普通流中起来 —— 让多个盒子(div)水平排列成一行)

      定位(将盒子在某一个置 自由的漂浮在其他盒子的上面)

      在 CSS 中,通过 float 中文, 浮 漏 特 属性定义浮动,语法如下:

      选择器 { float: 属性值; }
      
      属性值描述
      none元素不浮动(默认值
      left元素向浮动
      right元素向浮动

      float —— 浮漏特

      特点说明
      加了浮动的盒子是浮起来的,漂浮在其他标准流盒子的上面。
      加了浮动的盒子是不占位置的,它原来的位置漏给了标准流的盒子
      特别注意:浮动元素会改变display属性, 类似转换为了行内块,但是元素之间没有空白缝隙

      浮动元素与兄弟盒子的关系

      在一个父级盒子中,如果前一个兄弟盒子是:

      • 浮动的,那么当前盒子会与前一个盒子的顶部对齐;
      • 普通流的,那么当前盒子会显示在前一个兄弟盒子的下方。

      清除浮动

      父级盒子很多情况下,不方便给高度,但是子盒子浮动就不占有位置,最后父级盒子高度为0,就影响了下面的标准流盒子。清除浮动主要为了解决父级元素因为子级浮动引起内部高度为0 的问题。清除浮动之后, 父级就会根据浮动的子盒子自动检测高度。父级有了高度,就不会影响下面的标准流了。

      1.使用after伪元素清除浮动

      .clearfix:after { content: “”; display: block; height: 0; clear: both; visibility: hidden; }

      .clearfix {zoom: 1;} / IE6、7 专有 */

      2.使用双伪元素清除浮动

      .clearfix:before,.clearfix:after {
      content:"";
      display:table;
      }
      .clearfix:after {
      clear:both;
      }
      .clearfix {
      *zoom:1;
      }

      CSS属性书写顺序

      建议遵循以下顺序:

      1. 布局定位属性:display / position / float / clear / visibility / overflow(建议 display 第一个写,毕竟关系到模式)
      2. 自身属性:width / height / margin / padding / border / background
      3. 文本属性:color / font / text-decoration / text-align / vertical-align / white- space / break-word
      4. 其他属性(CSS3):content / cursor / border-radius / box-shadow / text-shadow / background:linear-gradient …

      5.定位

      定位也是用来布局的,它有两部分组成:定位=定位模式+边偏移

      在 CSS 中,通过 topbottomleftright 属性定义元素的边偏移:(方位名词)

      定位模式 (position) 语法:选择器 { position: 属性值; }

      定位模式(position)是否脱标占有位置移动位置基准模式转换(行内块)使用情况
      静态static不脱标,正常模式正常模式不能几乎不用
      相对定位relative不脱标,占有位置相对自身位置移动不能基本单独使用
      绝对定位absolute完全脱标,不占有位置相对于定位父级移动位置要和定位父级元素搭配使用
      固定定位fixed完全脱标,不占有位置相对于浏览器移动位置单独使用,不需要父级

      子绝父相 —— 子级绝对定位,父级要用相对定位。

      绝对定位的盒子居中

      position:relative;

      top:50%;

      left:50%;

      transform: translate(-50%,-50%);

      堆叠顺序(z-index)

      1. 属性值正整数负整数0,默认值是 0,数值越大,盒子越靠上;
      2. 如果属性值相同,则按照书写顺序,后来居上
      3. 数字后面不能加单位

      注意z-index 只能应用于相对定位绝对定位固定定位的元素,其他标准流浮动静态定位无效。

      6.css高级技巧

      透明度

      opacity:0~1;

      元素的显示与隐藏

      display 显示

      • display 设置或检索对象是否及如何显示。

        display: none 隐藏对象
        
        display:block 除了转换为块级元素之外,同时还有显示元素的意思。
        
      • 特点: 隐藏之后,不再保留位置。

      visibility 可见性

      • 设置或检索是否显示对象。

        visibility:visible ;  对象可视
        
        visibility:hidden;    对象隐藏
        
      • 特点: 隐藏之后,继续保留原有位置。

      overflow 溢出

      • 检索或设置当对象的内容超过其指定高度及宽度时如何管理内容。
      属性值描述
      visible不剪切内容也不添加滚动条
      hidden不显示超过对象尺寸的内容,超出的部分隐藏掉
      scroll不管超出内容否,总是显示滚动条
      auto超出自动显示滚动条,不超出不显示滚动条

      三者关系比较

      属性区别用途
      display隐藏对象,不保留位置配合后面js做特效,比如下拉菜单,原先没有,鼠标经过,显示下拉菜单, 应用极为广泛
      visibility隐藏对象,保留位置使用较少
      overflow只是隐藏超出大小的部分1. 可以清除浮动 2. 保证盒子里面的内容不会超出该盒子范围

      鼠标样式cursor

      属性值描述
      default小白 默认
      pointer小手
      move移动
      text文本
      not-allowed禁止

      轮廓线 outline

      语法:outline: none;

      防止拖拽文本域resize

      语法:

      vertical-align垂直对齐

      让文字居中对齐,是 text-align: center;

      vertical-align 垂直对齐,它只针对于行内元素或者行内块元素

      语法:vertical-align : baseline |top |middle |bottom

      图片、表单和文字对齐

      语法:vertical-align : middle

      去除图片底侧空白缝隙

      • 原因:

        图片或者表单等行内块元素,他的底线会和父级盒子的基线对齐。

        就是图片底侧会有一个空白缝隙。

      • 解决的方法就是:

        • 给img vertical-align:middle | top| bottom等等。 让图片不要和基线对齐。

      溢出的文字省略号显示

      1. 先强制一行内显示文本

        white-space: nowrap;

      2. 超出的部分隐藏

        overflow: hidden;

      3. 文字用省略号替代溢出的部分

        text-overflow: ellipsis;

      精灵技术

      首先我们知道,css精灵技术主要针对于背景图片,插入的图片img 是不需要这个技术的。

      1. 精确测量,每个小背景图片的大小和 位置。
      2. 给盒子指定小背景图片时, 背景定位基本都是 负值。

      滑动门

      一般的经典布局都是这样的:

      <li>
        <a href="#">
          <span>导航栏内容</span>
        </a>
      </li>
      

      css样式

      *{

      padding:0;
      margin:0;
      

      }
      body{

      background: url(images/wx.jpg) repeat-x;
      

      }
      .father {

      padding-top:20px;
      

      }
      li {

      padding-left: 16px;
      height: 33px;
      float: left;
      line-height: 33px;
      margin:0  10px;
      background: url(./images/to.png) no-repeat left ;
      

      }
      a {

      padding-right: 16px;
      height: 33px;
      display: inline-block;
      color:#fff;
      background: url(./images/to.png) no-repeat right ;
      text-decoration: none;
      

      }
      li:hover,
      li:hover a {

      background-image:url(./images/ao.png);
      

      }

      总结:

      1. a 设置 背景左侧,padding撑开合适宽度。
      2. span 设置背景右侧, padding撑开合适宽度 剩下由文字继续撑开宽度。
      3. 之所以a包含span就是因为 整个导航都是可以点击的。

      CSS三角形

      1. 我们用css 边框可以模拟三角效果
      2. 宽度高度为0
      3. 我们4个边框都要写, 只保留需要的边框颜色,其余的不能省略,都改为 transparent 透明就好了
      4. 为了照顾兼容性 低版本的浏览器,加上 font-size: 0; line-height: 0;

      阻止链接跳转

      需要给href添加 javascript:void(0); 或者 javascript:;

      7.网络商城项目总结

      网站ico图标

      1.使用ico图标

      • 首先把favicon.ico 这个图标放到根目录下。

      • 再html里面, head 之间 引入 代码。

      2.制作ico图标

      我们可以自己做的图片,转换为 ico图标,以便放到我们站点里面。

      方法步骤:

      • 首先把我们想要的切成图片。
      • 要把图片转换为 ico 图标,我们借助于第三方转换网站: http://www.bitbug.net/。 比特虫

      总结:

      代码:  <link rel="shortcut icon" href="favicon.ico"  type="image/x-icon"/>     
      

      注意:

      1. 她(它)是显示在浏览器中的网页图标。
      2. 它是图标形式,不是一个图片
      3. 位置是放到 head 标签中间。
      4. 后面的type=“image/x-icon” 属性可以省略。(我相信你也愿意省略。)
      5. 为了兼容性,请将favicon.ico 这个图标放到根目录下。

      网站优化三大标签

      1.网页title 标题

      一般不超过28个中文,最先出现的词语权重高,主关键词出现3次,辅关键词出现1次

      2.Description 网站说明

      电商网:

      <meta name="description" content="JD.COM-专业的综合网上购物商城,销售家电、数码通讯、电脑、家居百货、服装服饰、母婴、图书、食品等数万个品牌优质商品.便捷、诚信的服务,为您提供愉悦的网上购物体验!" />
      

      注意点:

      1. 描述中出现关键词,与正文内容相关,这部分内容是给人看的,所以要写的很详细,让人感兴趣, 吸引用户点击。
      2. 同样遵循简短原则,字符数含空格在内不要超过 120 个汉字。
      3. 补充在 title 和 keywords 中未能充分表述的说明.
      4. 用英文逗号 关键词1,关键词2

      3.Keywords 关键字

      Keywords是页面关键词,是搜索引擎关注点之一。Keywords应该限制在6~8个关键词左右,电商类网站可以多 少许。

      电商网:

      <meta name="Keywords" content="网上购物,网上商城,手机,笔记本,电脑,MP3,CD,VCD,DV,相机,数码,配件,手表,存储卡," />
      

      字体图标iconfont

      可以做出跟图片一样可以做的事情,改变透明度、旋转度,等…
      但是本质其实是文字,可以很随意的改变颜色、产生阴影、透明效果等等…
      本身体积更小,但携带的信息并没有削减。
      几乎支持所有的浏览器

      UI设计人员给我们svg文件,我们需要转换成我们页面能使用的字体文件, 而且需要生成的是兼容性的适合各个浏览器的。

      ​ 推荐网站: http://icomoon.io

      • icomoon字库

      IcoMoon成立于2011年,推出的第一个自定义图标字体生成器,它允许用户选择他们所需要的图标,使它们成一字型。 内容种类繁多,非常全面,唯一的遗憾是国外服务器,打开网速较慢。

      • 阿里icon font字库

      http://www.iconfont.cn/

      这个是阿里妈妈M2UX的一个icon font字体图标字库,包含了淘宝图标库和阿里妈妈图标库。可以使用AI制作图标上传生成。 一个字,免费,免费!!

      在样式里面声明字体: 告诉别人我们自己定义的字体(一定注意字体文件路径的问题)

      @font-face {
        font-family: 'icomoon';
        src:  url('fonts/icomoon.eot?7kkyc2');
        src:  url('fonts/icomoon.eot?7kkyc2#iefix') format('embedded-opentype'),
          url('fonts/icomoon.ttf?7kkyc2') format('truetype'),
          url('fonts/icomoon.woff?7kkyc2') format('woff'),
          url('fonts/icomoon.svg?7kkyc2#icomoon') format('svg');
        font-weight: normal;
        font-style: normal;
      }
      

      给盒子使用字体

      span {
      		font-family: "icomoon";
      	}
      

      过渡transition

      过渡动画: 是从一个状态 渐渐的过渡到另外一个状态

      语法格式:

      transition: 要过渡的属性  花费时间  运动曲线  何时开始;
      
      属性描述CSS
      transition简写属性,用于在一个属性中设置四个过渡属性。3
      transition-property规定应用过渡的 CSS 属性的名称。3
      transition-duration定义过渡效果花费的时间。默认是 0。3
      transition-timing-function规定过渡效果的时间曲线。默认是 “ease”。3
      transition-delay规定过渡效果何时开始。默认是 0。3

      运动曲线 默认是 ease 匀速:lineaar 逐渐慢下来:ease 加速:ease-in 减速:ease-out 先加后减速:ease-in-out

      获得焦点元素

      :focus 伪类 选择器用于选取获得焦点的元素 。 我们这里主要针对的是 表单元素

      :hover

      8.命令行、gulp

      命令行

      • 盘符: 就可以进入某个盘符

      • dir 列出目录中的所有文件

      • cd 切换文件夹(目录)

        • cd 目录名 可以进入指定目录,目录名可以是绝对路径也可以是相对路径
        • cd …/ 返回上一层目录
          • cd ./ 当前目录
          • cd / 返回根目录(盘符下)
      • md/mkdir 创建文件夹

      • rd/rmdir 删除文件夹

        • rd newdir 删除目录,如果目录中有其它内容会提示目录不是空的
        • rd /S newdir 删除目录,如果目录中有其它内容会提示newdir, 是否确认(Y/N)?,输入Y按回车删除
        • rd /S /Q newdir 静默删除目录,如果目录中有其它内容,不提示直接删除(此操作危险)
      • 创建文件

        • cd./>文件 比如 cd./>index.html 这样就可以创建一个html页面
      • 删除文件

        • del 文件名 比如 del index.html

      小技巧

      • 自动补全

        • 在敲出文件/目录前几个字母后,按下tab
          • 如果有以这前几个字母开头的文件/目录,系统会自动补全
          • 如果补全的文件/目录不是想要的可以继续按tab键,切换到下一个文件/目录,知道找到想要的为止
      • 曾经使用过的命令

        • 上/下光标键可以在曾经使用过的命令间来回切换
        • 如果不想执行当前的命令可以按ctrl + c 中断r
      • cls 清屏 (CLear Screen)

      • exit 退出

      • 快捷键 ctrl + c 终止当前操作

      • notepad 记事本

      • calc 计算器

      gulp

      Gulp.js 是一个自动化构建工具,开发者可以使用它在项目开发过程中自动执行常见任务。

      • 自动压缩代码
      • 自动打包、代码检查
      • 打开浏览器,并监视源码变化实时刷新
      • 部署到线上服务器

      安装

         node -v
      
      • 安装cnpm
      npm install -g cnpm --registry=https://registry.npm.taobao.org
      

      检测安装cnpm 是否成功

          cnpm -v
      

      ​ gulp -v

      本地环境搭建体验

      以下内容首先打开命令行,然后切换到项目的根目录,输入以下命令并运行

      • 初始化

        # 在当前目录自动生成一个package.json文件
        cnpm init -y
        
      • 安装插件

        # 当前项目中安装gulp
        cnpm install gulp --save-dev
        # 压缩html的插件
        cnpm install gulp-htmlmin --save-dev
        # 压缩css的插件
        cnpm install gulp-cssmin --save-dev
        # 自动打开浏览器,并实时刷新插件(浏览器同步测试工具)
        cnpm install browser-sync --save-dev
        
      • 配置文件

        在当前项目的根目录中创建一个gulpfile.js文件,如链接中文件

        gulpfile.js

      演示自动化构建

      # 自动化压缩和复制文件到发布目录dist
      gulp build
      # 开启测试用的服务器
      gulp dev
      

      三.htc3、移动Web开发

      1.html5标签

      语义化标签

      • header 头部标签
      • nav 导航标签
      • article 内容标签
      • section 块级标签
      • aside 侧边栏标签
      • footer 尾部标签

      h5表单属性

      • placeholder:占位符-提示信息

      • autofocus:自动获得焦点-一般页面中放1个

      • autocomplete 自动完成

        • 当用户在字段开始键入时,浏览器基于之前键入过的值,应该显示出在字段中填写的选项。
        • 默认已经打开 如 autocomplete=on 关闭 autocomplete =off
        • 需要放在表单内同时加上name属性
      • multiple:可以多选文件提交

        • 结合文件上传标签 <input type="file" > 一起使用
      • form属性,可以将输入标签放在表单的外面,还受到表单的管理

      • required:必填验证

      • novalidate:关闭验证

        • 在表单上添加该属性,那么在提交的时候就不会再执行 required验证
      • pattern:自定义验证-通过编写正则表达式自定义验证规则 一般和required同时使用

        • 表单事件

      audio 音频标签

      语法:

      <audio src="小猪佩奇.mp3" autoplay> </audio>
      

      支持的格式

      格式MIME-type
      MP3audio/mpeg
      Oggaudio/ogg
      Wavaudio/wav

      video 视频标签

      语法:

        <video src="小猪佩奇.mp4" autoplay controls ></video>
      

      支持的格式

      格式MIME-type
      MP4video/mp4
      WebMvideo/webm
      Oggvideo/ogg

      video常用属性、方法、事件

      属性方法事件
      duration 视频播放时长play 播放canplay 视频加载完毕 准备播放
      currentTime 当前播放进度pause 暂停timeupdate 播放时-持续触发
      volume 音量大小

      source标签

      可以通过在多媒体标签内加入source标签,用来指定多个播放路径,当第一个source标签的路径出错时,自动会切换到第二个source标签

          <!-- 当1.mp4出错时,自动切换到2.mp4 ... -->
          <video >
            <source src="1.mp4">
            <source src="2.mp4">
            <source src="3.mp4">
          </video>
      

      object-fit属性

      video标签视频内容宽度没有铺满video标签时,可以在css写上 该属性即可

          video {
            /* 让视频内容铺满整个video标签 */
            object-fit: fill;
          }
      

      公共属性

      以下属性 是要直接写在标签上的 如 autoplay controls

      <video src="小猪佩奇.mp4" autoplay controls ></video>
      
      属性描述
      autoplayautoplay如果出现该属性,则音频在就绪后马上播放。
      controlscontrols如果出现该属性,则向用户显示控件,比如播放按钮。
      looploop如果出现该属性,则每当音频结束时重新开始播放。
      mutedmuted规定视频输出应该被静音。
      preloadpreload如果出现该属性,则音频在页面加载时进行加载,并预备播放。如果使用 “autoplay”,则忽略该属性。
      srcurl要播放的音频的 URL。

      伪类选择符

      结构伪类选择器

      E:first-child —— 匹配父元素的第一个子元素

      E:nth-child(n) E:nth-last-child(n)

      匹配到父元素的第n个元素 或者 是倒数第n个元素(n也可以为公式、数字、关键字)

      常见的关键词有even偶数、odd奇数

      E:nth-of-type(n)

      • E:nth-child(n) 匹配父元素的第n个子元素E。
      • E:nth-of-type(n) 匹配同类型中的第n个同级兄弟元素E。

      属性选择器

      1. E[att] 选择具有att属性的E元素。
      2. E[att=“val”] 选择具有att属性且属性值等于val的E元素。
      3. E[att^=“val”] 选择具有att属性且属性值为以val开头的字符串的E元素。
      4. E[att$=“val”] 选择具有att属性且属性值为包含val的字符串的E元素
      5. E[att*=“val”] 选择具有att属性且属性值为包含val的字符串的E元素。

      伪元素选择器

      1. E::before 在E元素前插入一个元素
      2. E::after 在E元素后插入一个元素
      3. E::first-letter 选择到了E容器内的第一个字母
      4. E::first-line 选择到了E容器内的第一行文本

      想要让伪元素有效,必须遵循以下注意事项

      1. 伪元素只能给双标签加 不能给单标签加
      2. 伪元素的冒号前不能有空格 如 E ::before 这个写法是错误的
      3. 伪元素里面必须写上属性 content:"";

      2.2D、3D转换、动画animation

      2d移动 translate

      语法:div{

      transform: translate(50px,50px);
      

      }

      1. translate中的百分比单位是相对于自身元素的 translate:(50%,50%);
      2. translate类似定位,不会影响到其他元素的位置
      3. 对行内标签没有效果

      2d旋转 rotate

      使用步骤:

      1. 给元素添加转换属性 transform
      2. 属性值为 rotate(角度)transform:rotate(30deg) 顺时针方向旋转30度
      div{
            transform: rotate(0deg);
      }
      

      特点

      1. 角度为正时 顺时针 负时 为逆时针
      2. 默认旋转的中心点是元素的中心点

      转换中心 transform-origin

      该属性可以修改元素旋转的时候的中心点

      1. transform-origin:50% 50%; 默认值 元素的中心位置 百分比是相对于自身的宽度和高度
      2. transform-origin:top left; 左上角 和 transform-origin:0 0;相同
      3. transform-origin:50px 50px; 距离左上角 50px 50px 的位置
      4. transform-origin:0; 只写一个值的时候 第二个值默认为 50%;

      2d缩放 scale

      1. 给元素添加转换属性 transform
      2. 转换的属性值为 scale(宽的倍数,高的倍数) 如 宽变为两倍,高变为3倍 transform:scale(2,3)
      div{
          transform:scale(2,3);
      }
      

      小结

      1. transform:scale(1,1) 放大一倍 相对于没有放大
      2. transform:scale(2,2) 宽和高都放大了2倍
      3. transform:scale(2) 只写一个参数 第二个参数则和第一个参数一样 相当于 scale(2,2)
      4. transform:scale(0.5,0.5) 缩小
      5. transform:scale(-2,-2) 反向放大2倍 很少用负数 容易让人产生误解

      动画 animation

      用@keyframes定义动画,类似定义类选择器

         /* 1 声明动画函数 */
      
          @keyframes ani_div {
       0%{
          width: 100px;
          background-color: red;
        }
        50%{
          width: 150px;
          background-color: green;
        }
        100%{
          width: 300px;
          height: 300px;
          background-color: yellow;
        }
      }
       div {
            width: 200px;
            height: 200px;
            background-color: aqua;
            margin: 100px auto;
            /* 2 调用动画 */
            animation-name: ani_div;
            /* 持续时间 */
            animation-duration: 2s;
          }
      

      语法:

      1. 动画名

        设置要使用的动画名 animation-name:xxx;

      2. 持续时间

        设置动画播放的持续时间 animation-duration:3s

      3. 速度曲线

        和设置过渡的速度曲线一样 animation-timing-function:linear;

        • linear: 匀速
        • ease: 慢-快-慢 默认值
        • ease-in: 慢-快。
        • ease-out: 快-慢。
        • ease-in-out: 慢-快-慢。
      4. 延迟时间

        animation-delay: 0s;

      5. 循环次数

        设置动画播放的循环次数 animation-iteration-count: 2; infinite 为无限循环

      6. 循环方向

        animation-direction

        如在动画中定义了 0%:红色 100%:黑色 那么 当属性值为

        1. normal 默认值 红 -> 黑
        2. reverse 反向运行 黑 -> 红
        3. alternate 正-反-正… 红 -> 黑 -> 红…
        4. alternate-reverse 反-正-反… 黑 -> 红 -> 黑 …
        5. 以上与循环次数有关
      7. 动画等待或者结束的状态

        animation-fill-mode 设置动画在等待或者结束的时候的状态

        • forwards:动画结束后,元素样式停留在 100% 的样式
        • backwards: 在延迟等待的时间内,元素样式停留在 0% 的样式
        • both: 同时设置了 forwards和backwards两个属性值
      8. 暂停和播放

        animation-play-state 控制 播放 还是 暂停

        running 播放 paused 暂停

        复合写法

        animation: name duration timing-function delay iteration-count direction fill-mode;
        
        animation:动画名称 持续性时间 运动曲线 合适开始 播放次数 是否反方向 起始或结束的标志
        

        动画结束事件animationend

        元素在动画结束之后,会自动触发的事件 animationend

            var div = document.querySelector("div");
            div.addEventListener("animationend", function () {
              console.log("div的动画结束之后,触发");
            })
        

        css3兼容处理

        css3涉及到较多的新属性,某些低版本(如ie8以及以下)的浏览器对css3的支持程度不够,因此需要做以下处理

        添加对应的浏览器的前缀 常见前缀如下

        • 谷歌 -webkit
        • 火狐 -moz
        • IE -ms

        如对 border-radius 进行兼容性处理

              -webkit-border-radius: 30px 10px;
              -moz-border-radius: 30px 10px;
              -ms-border-radius: 30px 10px;
        	  // border-radius 一定要放在最后
              border-radius: 30px 10px;
        

        如果发现添加前缀也解决不了兼容性问题,那么就不要使用该css3属性

        3D转换

        3d移动 translate3d

        1. transform:translate3d(x,y,z) 其中 x y z 分别指要移动的轴的方向的距离
        2. translform:translateX(100px) 仅仅是移动在x轴上移动
        3. translform:translateY(100px) 仅仅是移动在Y轴上移动
        4. translform:translateZ(100px) 仅仅是移动在Z轴上移动

      视距 perspertive

      perspertive 就是用来设置 物体 的距离

      写在被观察元素的父盒子里

      左手准则

      要判断某元素沿着x轴是怎么旋转的

      1. 左手的手拇指指向 x轴的正方向
      2. 其余手指的弯曲方向就是该元素沿着x轴旋转的方向了

      3d旋转 rotate3d

      语法:

      1. transform:rotateX(45deg); 沿着x轴正方向旋转 45度
      2. transform:rotateY(45deg) 沿着y轴正方向旋转 45deg
      3. transform:rotateZ(45deg) 沿着Z轴正方向旋转 45deg
      4. transform:rotate3d(x,y,z,deg) 沿着自定义轴旋转 deg为角度 了解即可

      3D缩放 scale3d

      语法:

      1. transform: scale3d(1 ,1,2); 宽,高 缩放一倍,厚度放大两倍
      2. transform: scaleX(1) 只缩放宽
      3. transform: scaleY(1) 只缩放高
      4. transform: scaleZ(1) 只缩放厚

      视距原点 perspective-origin

      视距原点 可以设置 人 站在x轴和y轴的位置

      1. 视距原点和视距一样,也是设置给要观察元素的父元素
      2. perspective-origin:center center; 默认值是元素的中心点
      3. perspective-origin:10px; 指定了一个参数的时候,第二个参数默认为center 也就是50%;
      4. perspective-origin:10% %; 百分比都是相对于自身的宽度和高度

      转换样式(3D呈现) transform-style

      控制子元素是否开启3维立体环境

      • transform-style: flat; 平面模式 - 不开启3维立体环境
      • transform-style: preserve-3d; 3维立体环境

      3.流式布局

      布局视口 layout viewport

      移动设备的浏览器都默认设置了一个布局视口,用于解决早期的PC端页面在手机上显示的问题。

      视觉视口 visual viewport

      它是用户正在看到的网站的区域。注意:是网站的区域。

      我们可以通过缩放去操作视觉视口,但不会影响布局视口,布局视口仍保持原来的宽度。

      理想视口 ideal viewport

      理想视口,对设备来讲,是最理想的视口尺寸

      需要手动添写meta视口标签通知浏览器操作

      meta视口标签的主要目的:布局视口的宽度应该与理想视口的宽度一致,简单理解就是设备有多宽,我们布局的视口就多宽

      总结:我们开发最终会用理想视口,而理想视口就是将布局视口的宽度修改为视觉视口

      meta标签

      <meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
      
      属性解释
      width宽度设置的是viewport宽度,可以设置device-width特殊值
      initial-scale初始缩放比,大于0的数字
      maximum-scale最大缩放比,大于0的数字
      minimum-scale最小缩放比,大于0的数字
      user-scalable用户是否可以缩放,yes或no(1或0)

      最标准的viewport设置

      • 视口宽度和设备保持一致
      • 视口的默认缩放比例1.0
      • 不允许用户自行缩放
      • 最大允许的缩放比例1.0
      • 最小允许的缩放比例1.0

      二倍图

      物理像素&物理像素比

      物理像素点指的是屏幕显示的最小颗粒,是物理真实存在的。

      物理像素比:一个px的能显示的物理像素点的个数,称为物理像素比或屏幕像素比

      背景缩放background-size

      background-size 属性规定背景图像的尺寸

      background-size: 背景图片宽度 背景图片高度;
      

      单位: 长度|百分比|cover|contain;

      cover把背景图像扩展至足够大,以使背景图像完全覆盖背景区域。

      contain把图像图像扩展至最大尺寸,以使其宽度和高度完全适应内容区域

      CSS3盒子模型

      传统模式宽度计算:盒子的宽度 = CSS中设置的width + border + padding

      CSS3盒子模型: 盒子的宽度= CSS中设置的宽度width 里面包含了 border 和 padding

      /*CSS3盒子模型(用这个)*/
      box-sizing: border-box;
      /*传统盒子模型*/
      box-sizing: content-box;
      

      移动端特殊样式

          /*CSS3盒子模型*/
          box-sizing: border-box;
          -webkit-box-sizing: border-box;
          /*点击高亮我们需要清除清除  设置为transparent 完成透明*/
          -webkit-tap-highlight-color: transparent;
          /*在移动端浏览器默认的外观在iOS上加上这个属性才能给按钮和输入框自定义样式*/
          -webkit-appearance: none;
          /*禁用长按页面时的弹出菜单*/
          img,a { -webkit-touch-callout: none; }
      

      流式布局方式

      流式布局,就是百分比布局,也称非固定像素布局。

      通过盒子的宽度设置成百分比来根据屏幕的宽度来进行伸缩,不受固定像素的限制,内容向两侧填充。

      4.flex布局

      • flex 是 flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性,任何一个容器都可以指定为 flex 布局。
      • 当我们为父盒子设为 flex 布局以后,子元素的 float、clear 和 vertical-align 属性将失效。
      • flex布局又叫伸缩布局 、弹性布局 、伸缩盒布局 、弹性盒布局
      • 采用 Flex 布局的元素,称为 Flex 容器(flex

      container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex
      item),简称"项目"。

      总结:就是通过给父盒子添加flex属性,来控制子盒子的位置和排列方式

      父项常见属性

      • flex-direction:设置主轴的方向
      子属性属性值
      row默认值从左到右
      row-reverse从右到左
      column从上到下
      column-reverse从下到上
      • justify-content:设置主轴上的子元素排列方式
      子属性属性值
      flex-start默认值,从头部开始,如果主轴是X,则从左往右
      flex-end从尾部开始排列
      center在主轴居中对齐,如果主轴是X轴,水平居中
      space-around平分剩余空间
      space-bet先两边贴边再平分剩余空间
      • flex-wrap:设置子元素是否换行

      默认项目都排在一条线(又称”轴线”)上。

      flex-wrap属性定义,flex布局中默认是不换行的

      nowrap 不换行

      wrap 换行

      • align-items:设置侧轴上的子元素排列方式(单行)

      flex-start 从头部开始

      flex-end 从尾部开始

      center 居中显示

      stretch 拉伸

      • align-content:设置侧轴上的子元素的排列方式(多行)

      只能用于子项出现 换行 的情况(多行),在单行下是没有效果的。

      子属性属性值
      flex-start默认值在侧轴的头部开始排列
      flex-end从侧轴尾部开始排列
      center在侧轴中间显示
      space-around子项在侧轴平分剩余空间
      space-bet子项在侧轴先两边贴边再平分剩余空间
      stretch设置子项元素高度平分父元素高度
      • flex-flow:复合属性,相当于同时设置了 flex-direction 和 flex-wrap
      flex-flow:row wrap;
      

      子项常见属性

      • flex子项目占的份数

      flex 属性定义子项目分配剩余空间,用flex来表示占多少份数。

      .item {
          flex: <number>; /* 默认值 0 */
      }
      
      • align-self控制子项自己在侧轴的排列方式

      align-self 属性允许单个项目有与其他项目不一样的对齐方式,可覆盖 align-items 属性。

      默认值为 auto,表示继承父元素的 align-items 属性,如果没有父元素,则等同于 stretch。

      span:nth-child(2) {
            /* 设置自己在侧轴上的排列方式 */
            align-self: flex-end;
      }
      
      • order属性定义子项的排列顺序(前后顺序)

      数值越小,排列越靠前,默认为0。

      注意:和 z-index 不一样。

      5.rem布局

      rem单位

      rem (root em)是一个相对单位,类似于em,em是父元素字体大小。

      不同的是rem的基准是相对于html元素的字体大小。

      比如,根元素(html)设置font-size=12px; 非根元素设置width:2rem; 则换成px表示就是24px。

      媒体查询

      • 用 @media开头 注意@符号
      • mediatype 媒体类型
      • 关键字 and not only
      • media feature 媒体特性必须有小括号包含
      @media mediatype and|not|only (media feature) {
          CSS-Code;
      }
      

      mediatype 查询类型

      ​ 将不同的终端设备划分成不同的类型,称为媒体类型

      all 用于所有设备

      print 用于打印机和打印预览

      scree 用于电脑屏幕,平板电脑,只能手机等

      关键字

      ​ 关键字将媒体类型或多个媒体特性连接到一起做为媒体查询的条件。

      • and:可以将多个媒体特性连接到一起,相当于“且”的意思。
      • not:排除某个媒体类型,相当于“非”的意思,可以省略。
      • only:指定某个特定的媒体类型,可以省略。

      媒体特性

      width 定义输出设备中页面可见区域的宽度

      min-width 定义输出设备中页面最小可见区域宽度

      max-width 定义输出设备中页面最大可见区域宽度

      less 基础

      Less安装

      ①安装nodejs,可选择版本(8.0),网址:http://nodejs.cn/download/

      ②检查是否安装成功,使用cmd命令(win10是window+r 打开运行输入cmd) —输入“node –v”查看版本即可

      ③基于nodejs在线安装Less,使用cmd命令“npm install -g less”即可

      ④检查是否安装成功,使用cmd命令“ lessc -v ”查看版本即可

      Less 使用之变量

      变量是指没有固定的值,可以改变的。因为我们CSS中的一些颜色和数值等经常使用。

      @变量名:值;
      
      • 必须有@为前缀
      • 不能包含特殊字符
      • 不能以数字开头
      • 大小写敏感
      @color: pink;
      

      Less 编译 vocode Less 插件

      Easy LESS 插件用来把less文件编译为css文件

      安装完毕插件,重新加载下 vscode。

      只要保存一下Less文件,会自动生成CSS文件。

      Less 嵌套 :如果遇见 (交集|伪类|伪元素选择器) ,利用&进行连接

      Less 运算

      任何数字、颜色或者变量都可以参与运算。就是Less提供了加(+)、减(-)、乘(*)、除(/)算术运算。

      • 乘号(*)和除号(/)的写法
      • 运算符中间左右有个空格隔开 1px + 5
      • 对于两个不同的单位的值之间的运算,运算结果的值取第一个值的单位
      • 如果两个值之间只有一个值有单位,则运算结果就取该单位

      6.响应式布局

      使用媒体查询针对不同宽度的设备进行布局和样式的设置,从而适配不同设备的目的。

      设备的划分情况:

      • 小于768的为超小屏幕(手机)
      • 768~992之间的为小屏设备(平板)
      • 992~1200的中等屏幕(桌面显示器)
      • 大于1200的宽屏设备(大桌面显示器)

      父容器版心的尺寸划分

      • 超小屏幕(手机,小于 768px):设置宽度为 100%
      • 小屏幕(平板,大于等于 768px):设置宽度为 750px
      • 中等屏幕(桌面显示器,大于等于 992px):宽度设置为 970px
      • 大屏幕(大桌面显示器,大于等于 1200px):宽度设置为 1170px

      Bootstrap

      Bootstrap 来自 Twitter(推特),是目前最受欢迎的前端框架。Bootstrap 是基于HTML、CSS 和 JAVASCRIPT 的,它简洁灵活,使得 Web 开发更加快捷。

      bootstrap基本使用

      1. 创建文件夹结构

      2. 创建 html 骨架结构

      3. 引入相关样式文件

        <!-- Bootstrap 核心样式-->
        <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
        
      4. 书写内容

      bootstrap布局容器

      .container

      • 响应式布局的容器 固定宽度
      • 大屏 ( >=1200px) 宽度定为 1170px
      • 中屏 ( >=992px) 宽度定为 970px
      • 小屏 ( >=768px) 宽度定为 750px
      • 超小屏 (100%)

      .container-fluid

      • 流式布局容器 百分百宽度
      • 占据全部视口(viewport)的容器。

      bootstrap栅格系统

      • 按照不同屏幕划分为1~12 等份
      • 行(row) 可以去除父容器作用15px的边距
      • xs-extra small:超小; sm-small:小; md-medium:中等; lg-large:大;
      • 列(column)大于 12,多余的“列(column)”所在的元素将被作为一个整体另起一行排列
      • 每一列默认有左右15像素的 padding
      • 可以同时为一列指定多个设备的类名,以便划分不同份数 例如 class=“col-md-4 col-sm-6”

      列偏移

      使用 .col-md-offset-* 类可以将列向右侧偏移。这些类实际是通过使用 * 选择器为当前元素增加了左侧的边距(margin)。

       <!-- 列偏移 -->
        <div class="row">
            <div class="col-lg-4">1</div>
            <div class="col-lg-4 col-lg-offset-4">2</div>
        </div>
      

      列排序

      通过使用 .col-md-push-* 和 .col-md-pull-* 类就可以很容易的改变列(column)的顺序。

       <!-- 列排序 -->
        <div class="row">
            <div class="col-lg-4 col-lg-push-8">往左侧推</div>
            <div class="col-lg-8 col-lg-pull-4">往右侧推</div>
        </div>
      

      响应式(隐藏)工具

      类名超小屏小屏中屏大屏
      .hidden-xs隐藏可见可见可见
      .hidden-sm可见隐藏可见可见
      .hidden-md可见可见隐藏可见
      .hidden-lg可见可见可见隐藏

      语法: class="hidden-xs“

      与之相反的是 visible-xs/sm/md/lg

      四.js基础

      1.数据类型

      JS组成

      ECMAScript——JavaScript语法

      DOM——页面文档对象模型

      BOM——浏览器对象模型

      数据存储单位

      大小关系:bit < byte < kb < GB < TB<.....
      
      • 位(bit): 1bit 可以保存一个 0 或者 1 (最小的存储单位)
      • 字节(Byte):1B = 8b
      • 千字节(KB):1KB = 1024B
      • 兆字节(MB):1MB = 1024KB
      • 吉字节(GB): 1GB = 1024MB
      • 太字节(TB): 1TB = 1024GB

      输入输出语句

      方法说明归属
      alert(msg)浏览器弹出警示框浏览器
      console.log(msg)浏览器控制台打印输出信息浏览器
      prompt(info)浏览器弹出输入框,用户可以输入浏览器

      alert() 主要用来显示消息给用户,console.log() 用来给程序员自己看运行时的消息。

      声明变量

      //  声明变量  
      var age; //  声明一个 名称为age 的变量     
      

      赋值

      age = 10; // 给 age  这个变量赋值为 10          
      

      变量的初始化

      var age  = 18;  // 声明变量同时赋值为 18          
      
      声明一个变量并赋值, 我们称之为变量的初始化。
      

      数据类型简介

      • Nunber 数字型,包含整型和浮点型,在JS中八进制前面加0,十六进制前面加 0x
      alert(Number.MAX_VALUE); // 1.7976931348623157e+308
      alert(Number.MIN_VALUE); // 5e-324
      alert(Infinity);  // Infinity 无穷大
      alert(-Infinity); // -Infinity 无穷小
      alert(NaN);       // NaN , Not a number,代表一个非数值
      

      isNaN用来判断一个变量是否为非数字的类型,返回 true 或者 false

      语法: var 变量名A = isNaN(变量名B)

      • String 字符串型

        转义符解释说明
        \n换行符,n 是 newline 的意思
        \ \斜杠 \
        ’ 单引号
        "”双引号
        \ttab 缩进
        \b空格 ,b 是 blank 的意思

      字符串长度 —— 语法:语法: var 变量名A = 变量名B.length

      字符串拼接

      ​ 多个字符串之间可以使用 + 进行拼接,其拼接方式为 字符串 + 任何类型 = 拼接之后的新字符串

      ​ 拼接前会把与字符串相加的任何类型转成字符串,再拼接成一个新的字符串

      ​ 如果变量两侧都有字符串拼接,口诀“引引加加 ”,删掉数字,变量写加中间

      • Boolean 布尔值类型,如true、false,等价于1和0、
      • Undefined 未定义——一个声明后没有被赋值的变量会有一个默认值undefined
      • Null 空值——一个声明变量给 null 值,里面存的值为空

      获取变量数据类型

      typeof 可用来获取检测变量的数据类型

      var num = 18;
      console.log(typeof num) // 结果 number      
      

      数据类型转换

      • 转换为字符串

        1.toString() 语法:alert(变量名.toString())

        2.String()强制转换 语法:alert(String(变量名))

        3.加号拼接字符串:和字符串拼接的结果都是字符串(隐式转换)

      • 转换为数字型

        1.parseInt(string)函数 语法:parseInt(’string‘)

        2.parseFloat(string)函数 语法:parseInt(’string‘)

        3.Number()强制转换 语法:Numer(‘string’)

        4.js隐式转换:利用算术运算隐式转换为数值型 比如:‘12’-0

      • 转换为布尔型

        Boolean()函数 语法:Boolean(‘string’)

      关键字

      包括:break、case、catch、continue、default、delete、do、else、finally、for、function、if、in、instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with 等。
      

      2.运算符、流程控制、循环

      递增运算符

      ++num 前置递增,就是自加1,类似于 num = num + 1,但是 ++num 写起来更简单。

      使用口诀:先自加,后返回值

      num++ 后置递增,就是自加1,类似于 num = num + 1 ,但是 num++ 写起来更简单。

      使用口诀:先返回原值,后自加

      比较运算符

      < > <== >== == != === !==

      逻辑运算符

      与&& 或|| 非!

      流程控制

      if 语句

      // 适合于检查多重条件。
      if (条件表达式1) {
          语句1} else if (条件表达式2)  {
          语句2} else if (条件表达式3)  {
         语句3....
      } else {
          // 上述条件都不成立执行此处代码
      }
      

      三元表达式

      表达式1 ? 表达式2 : 表达式3;
      

      switch分支流程控制

        switch( 表达式 ){ 
            case value1:
                // 表达式 等于 value1 时要执行的代码
                break;
            case value2:
                // 表达式 等于 value2 时要执行的代码
                break;
            default:
                // 表达式 不等于任何一个 value 时要执行的代码
        }
      

      注意: 执行case 里面的语句时,如果没有break,则继续执行下一个case里面的语句。

      for循环

      for(初始化变量; 条件表达式; 操作表达式 ){
          //循环体
      }
      

      while循环

      while (条件表达式) {
          // 循环体代码 
      }
      

      do-while循环

      do {
          // 循环体代码 - 条件表达式为 true 时重复执行循环体代码
      } while(条件表达式);
      

      continue

      continue 关键字用于立即跳出本次循环,继续下一次循环(本次循环体中 continue 之后的代码就会少执行一次)

      break

      立即跳出整个循环(循环结束)

      3.数组、函数

      创建数组

      • 利用 new 创建数组

        var 数组名 = new Array()var arr = new Array();   // 创建一个新的空数组
        

        注意 Array () ,A 要大写

      • 利用数组字面量创建数组

        //1. 使用数组字面量方式创建空的数组
        var  数组名 = []//2. 使用数组字面量方式创建带初始值的数组
        var  数组名 = ['小白','小黑','大黄','瑞奇'];
        

      数组中新增元素

        数组[ 数组.length ] = 新数据;
      

      函数的使用

      声明函数

      // 声明函数
      function 函数名() {
          //函数体代码
      }
      

      调用函数

      // 调用函数
      函数名();  // 通过调用函数名来执行函数体代码
      

      函数的参数

      • 形参:函数定义时设置接收调用时传入
      • 实参:函数调用时传入小括号内的真实数据

      函数的返回值

      return 语句

      • 在使用 return 语句时,函数会停止执行,并返回指定的值
      • 如果函数没有 return ,返回的值是 undefined

      arguments的使用

      当不确定有多少个参数传递的时候,可以用 arguments 来获取

      arguments展示形式是一个伪数组,可以进行遍历

      • 具有 length 属性
      • 按索引方式储存数据
      • 不具有数组的 push , pop 等方法

      4.作用域、预解析、对象

      JavaScript(es6前)中的作用域有两种:

      ​ 全局作用域 在函数内部没有声明直接赋值的变量属于全局变量

      ​ 局部作用域(函数作用域)

      预解析

      • 预解析:在当前作用域下, JS 代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中进行提前声明或者定义。

      • 代码执行: 从上到下执行JS语句。

        预解析会把变量和函数的声明在代码执行之前执行完成。

      对象

      所有的事物都是对象,对象是由属性和方法组成的

      • 属性:事物的特征,在对象中用属性来表示(常用名词)
      • 方法:事物的行为,在对象中用方法来表示(常用动词)

      创建对象的三种方式

      1.利用字面量创建对象

      var 对象名 = {
         属性1:属性值1;
        属性2:属性值2;
        .......
          sayHi : function(){
              alert('大家好啊~');
          }
      };
      

      调用对象——对象名.属性名 或 对象名[‘属性名’]

      调用对象方法——对象名.方法名()

      2.利用 new Object 创建对象

      var 对象名 = new Obect();
      

      通过内置构造函数Object创建对象,此时变量已经保存了创建出来的空对象

      通过对象操作属性和方法的方式,来为对象增加属性和方法

      比如——对象名1.属性1=’XXX‘;

      3.利用构造函数创建对象

      function 构造函数名(形参1,形参2,形参3) {
           this.属性名1 = 参数1;
           this.属性名2 = 参数2;
           this.属性名3 = 参数3;
           this.方法名 = 函数体;
      }
      

      构造函数的调用格式

      var obj = new 构造函数名(实参1,实参2,实参3)
      

      以上代码中,obj即接收到构造函数创建出来的对象

      遍历对象

      其语法如下:
      
      for (var 变量 in 对象名字) {
          // 在此执行代码
      }
      

      5.内置对象

      Math对象

      属性、方法名功能
      Math.PI圆周率
      Math.floor()向下取整
      Math.ceil()向上取整
      Math.round()四舍五入版 就近取整 注意 -3.5 结果是 -3
      Math.abs()绝对值
      Math.max()/Math.min()求最大和最小值
      Math.random()获取范围在[0,1)内的随机数
      // Math随机数方法  包含两端的2个数字
      function getRandom(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min; 
      }
       console.log(getRandom(1, 10));
      

      日期对象

      • 获取当前时间必须实例化:
      var now = new Date();
      
      • 获取指定时间的日期对象
      var future = new Date('2019/5/1');//或者 ('2019-10-10 8:8:8')
      
       // 返回当前年份
              console.log(date.getFullYear());
              // 返回当前月份 数值比实际月份小1  需要+1
              console.log(date.getMonth() + 1);
              // 返回当前日期是本月的多少日
              console.log(date.getDate());
              // 返回当前日期是周几  注意:返回当前是周几  周日返回值为0
              console.log(date.getDay());
               // 返回当前小时
              console.log(date.getHours());
      		  // 返回当前分钟
              console.log(date.getMinutes());
      		  // 返回当前秒钟
              console.log(date.getSeconds());
      
      • 获取总毫米数

      基于1970年1月1日(世界标准时间)起的毫秒数

      获取总毫秒数如下

      // 实例化Date对象
      var now = new Date();
      // 1. 用于获取对象的原始值
      console.log(date.valueOf())	
      console.log(date.getTime())	
      // 2. 简单写可以这么做
      var now = + new Date();			
      // 3. HTML5中提供的方法,有兼容性问题
      var now = Date.now();
      

      数组对象

      检测是否为数组

      1.instanceof 可以判断一个对象是否是某个构造函数的实例 返回值为true或者false

      语法:数组名 instanceof Array

      比如:console.log(arr instanceof Array);

      2**.Array.isArray(数组名)**用于判断一个对象是否为数组 返回值为true或者false 是 HTML5 中提供的方法

      添加删除数组元素

      方法名说明返回值
      push(参数1…)末尾添加一个或多个元素–数组名.push(要添加的)新的长度
      pop()删除最后一个元素,数组长度减一删除的元素值
      unshift(参数1…)开头添加一个或多个元素新的长度
      shift()删除第一个元素,数组长度减一第一个元素值

      注意:push、unshift为增加元素方法;pop、shift为删除元素的方法

      数组排序

      方法名说明
      reverse()颠倒数组中元素顺序
      sort()对数组的元素进行排序

      注意:sort方法需要传入参数来设置升序、降序排序

      • 如果传入“function(a,b){ return a-b;}”,则为升序
      • 如果传入“function(a,b){ return b-a;}”,则为降序

      数组转换为字符串

      1.toString() 把数组转换成字符串,逗号分隔每一项

      2.join(‘分隔符’) 把数组中的所有元素转换为一个字符串

      注意:二者均返回一个字符串,join方法如果不传入参数,则按照 “ , ”拼接元素

      数组对象转换为字符串格式

      JSON.stringify()

      其他方法

      数组连接 concat(‘连接内容’)

      数组截取字符串 slice(截取的起始位置,截取的数量)

      数组替换 replace(‘被替换的字符’,‘替换为的字符’) 只会替换第一个

      数组根据索引号删除相关内容 splice(索引号,从索引号处开始要删除的数量 )

      字符串对象

      js 会把基本数据类型包装为复杂数据类型

      字符串转换为数组对象

      JSON.parse()

      字符串操作方法

      连接字符串 str.concat(‘连接内容’)

      查找字符串 str.substr(start,length) 从start位置开始,length取的个数

      截取字符串 slice(start,end) 从start位置开始,截取到end位置,end取不到

      替换字符串 str.replace(‘被替换的字符’,‘替换为的字符’) 只会替换第一个

      字符转换为数组 str.split(‘分隔符’)

      五.Web API

      API是给程序员提供的一种工具,以便能更轻松的实现想要完成的功能

      1.获取元素、事件基础、操作元素

      获取元素

      根据ID获取

      语法:document.getElementById(id)
      返回值:元素对象 或 null
      

      根据标签名获取元素

      语法:document.getElementsByTagName('标签名')  或者 element.getElementsByTagName('标签名') 
      返回值:元素对象集合(伪数组,数组元素是元素对象)
      

      根据类名获取元素 (h5新增)

      document.getElementsByClassName(‘类名’) //返回元素对象集合

      根据选择器获取元素 (h5新增)

      document.querySelector(‘选择器’) //返回第一个元素对象

      document.querySelectorAll(‘选择器’) //根据指定选择器返回

      获取body元素

      document.body

      获取html元素

      document.documentElement

      事件基础

      事件三要素

      • 事件源(谁):触发事件的元素
      • 事件类型(什么事件): 例如 click 点击事件
      • 事件处理程序(做啥):事件触发后要执行的代码(函数形式),事件处理函数

      执行事件的步骤

      1.获取事件源

      2.注册事件(绑定事件)

      3.添加事件处理程序(采取函数赋值形式)

      常见的鼠标事件

      鼠标事件触发条件
      onclick鼠标点击左键触发
      onmouseover鼠标经过触发
      onmouseout鼠标离开触发
      onfocus获得鼠标焦点触发
      onblur失去鼠标焦点触发
      onmousemove鼠标移动触发

      修改元素内容(获取或设置)

      element.innerText 从起始到终止位置的内容,但不识别html标签,空格和换行也会去掉

      element.innerHTML 从起始到终止位置的内容,但识别html标签,空格和换行也会保留

      属性操作

      获取属性的值: 元素对象.属性名

      设置属性的值: 元素对象.属性名=值

      样式属性操作

      element.style 行内样式操作

      element.className 类名样式操作

      2.自定义属性操作、节点操作

      排他思想

      如果有同一组元素,我们想要某一个元素实现某种样式, 需要用到循环的排他思想算法:

      1. 所有元素全部清除样式(干掉其他人)
      2. 给当前元素设置样式 (留下我自己)
      3. 注意顺序不能颠倒,首先干掉其他人,再设置自己

      自定义属性操作

      获取属性值

      1.element.属性 //获取内置属性(元素本身自带的属性)

      2.element.getAttribute(’属性值’) //主要获得自定义的属性,程序员自定义的属性

      设置属性值

      1.element.属性 = ‘值’ //设置内置属性值

      2.element.setAttribute(’属性值’,‘值’) //主要设置自定义的属性

      移出属性

      element.removeAttribute(‘属性’);

      H5自定义属性

      H5规定自定义属性data-开头作为属性名并且赋值

      比如:element.setAttribute('data-index',2)
      

      获取H5自定义属性

      element.dataset.属性名

      element.dataset[’‘属性名’]

      节点操作

      元素节点 nodeType为1 //实际开发中的主要操作对象

      属性节点 nodeType为2

      文本节点 nodeType为3(包含文字、空格、换行等)

      父级节点

      node.parentNode //返回最近的一个父节点,没有则返回null

      子节点

      1.parentNode.childNodes //会返回所有节点

      2.parentNode.children //只返回子元素节点,其余节点不返回,重点使用这个

      第1个子节点:parentNode.firstElementChild

      最后一个子节点:parentNode.lastElementChild

      兄弟节点

      node.nextElementSibling 返回下一个兄弟元素节点

      node.previousElementSibling 返回上一个兄弟元素节点

      创建节点

      document.createElement(‘tagName’)

      添加节点

      node.appendChild(节点名) //将一个节点添加到指定父节点的子节点列表末尾,类似于css里的after伪元素

      node.insertBefore(节点名,指定元素) //将一个节点添加到父节点指定的子节点前面,类似于css里的before伪元素

      删除节点

      node.removeChild(child)
      

      说明:node.removeChild() 方法从 node节点中删除一个子节点,返回删除的节点。

      复制(克隆)节点

      node.cloneNode() ; // 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容

      node.cloneNode(true); //括号为true 深拷贝 复制标签复制里面的内容

      document.write创建元素

      • 语法:

        • document.write()
        • element.innerHTML
        • document.createElement()
      • 区别:

        1. document.write 是直接将内容写入页面的内容流,界面加载完成之后,再写入,这样它会导致页面全部重绘
        2. innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘
        3. innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
        4. createElement() 创建多个元素效率稍低一点点,但是结构更清晰
        5. 总结不同浏览器下,innerHTML 效率要比 creatElement 高

      3.事件高级

      方法事件监听addEventListener()

      同一个元素同一个事件可以注册多个监听器(事件处理程序)

      // 参数1:事件类型,它是字符串 必定加引号 而且不带on
      // 参数2:事件处理程序
      btns[1].addEventListener('click', function() {
      	alert(22);
      })
      btns[1].addEventListener('click', function() {
      	alert(33);
      })
      

      attachEvent()事件监听

      • 语法:
       eventTarget.attachEvent(eventNameWithOn, callback) 
       比如: btns[2].attachEvent('onclick', function() {
              alert(11);
          }) //  attachEvent ie9以前的版本支持  这里的事件需要带on
      

      删除事件(解绑事件)

      1. eventTarget.removeEventListener(type, listener[, useCapture]);
       //针对addEventListener()
      2. eventTarget.detachEvent(eventNameWithOn, callback);
      //针对attachEvent()
      

      DOM 事件流

      1. 捕获阶段
      2. 当前目标阶段
      3. 冒泡阶段

      事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即 DOM 事件流

      注意:

      1. JS 代码中只能执行捕获或者冒泡其中的一个阶段。
      2. onclick 和 attachEvent 只能得到冒泡阶段。(理解:只在冒泡阶段触发)
      3. addEventListener(type, listener[, useCapture])第三个参数如果是 true,表示在事件捕获阶段调用事件处理程序;如果是 false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序。
      4. 实际开发中我们很少使用事件捕获,我们更关注事件冒泡
      5. 有些事件是没有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave

      事件对象

        eventTarget.onclick = function(event) {
           // 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt 
        } 
        eventTarget.addEventListener('click', function(event) {
          // 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt 
        }

      事件对象的属性和方法

      事件对象属性方法说明
      e.target返回触发事件的对象 标准
      e.srcElement返回触发事件的对象 非标准 ie6-8使用
      e.type返回事件的类型 比如click mouseover 不带on
      e.cancelBubble=true该属性阻止冒泡排序 非标准 ie6-8使用
      e.returnValue=false阻止默认事件(默认行为) 非标准 ie6-8使用 比如不让链接跳转
      e.preventDefault()阻止默认事件(默认行为) 标准 比如不让链接跳转
      e.stopPropagation()阻止冒泡排序

      e.target 和 this 的区别

      • this 是事件绑定的元素(绑定这个事件处理函数的元素) 。
      • e.target 是事件触发的元素(比如click事件中点击的对象)。

      阻止默认行为

      1. e.preventDefault(); //标准写法 一般用这个
      2. e.returnValue = false; // 低版本浏览器 ie678
      3. return false; //return后面的不执行
          <a href="http://www.baidu.com">百度</a>
          <script>
              // 2. 阻止默认行为 让链接不跳转 
              var a = document.querySelector('a');
              a.addEventListener('click', function(e) {
                   e.preventDefault(); //  dom 标准写法
              });
              // 3. 传统的注册方式
              a.onclick = function(e) {
                  // 普通浏览器 e.preventDefault();  方法
                  e.preventDefault();
                  // 低版本浏览器 ie678  returnValue  属性
                  e.returnValue = false;
                  // 我们可以利用return false 也能阻止默认行为 没有兼容性问题
                  return false;
              }
          </script>
      

      阻止事件冒泡

      1. e.stopPropagation() //标准写法
      2. e.cancelBubble = true; //非标准写法
       var son = document.querySelector('.son');
      		// 给son注册单击事件
              son.addEventListener('click', function(e) {
                  alert('son');
                  e.stopPropagation(); 
                  window.event.cancelBubble = true; 
              }, false);
      
      • 阻止事件冒泡的兼容性处理
        if(e && e.stopPropagation){
            e.stopPropagation();
        }else{
            window.event.cancelBubble = true;
        }
      

      事件委托

      事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。

      禁止鼠标右键菜单

      contextmenu事件:鼠标右键菜单事件。主要控制应该何时显示上下文菜单(右键菜单),主要用于程序员取消默认的上下文菜单

      document.addEventListener('contextmenu', function(e) {
      	e.preventDefault();
      })
      

      禁止鼠标选中

      selectstart 事件:鼠标选中事件,用于界面文字防止选中

      document.addEventListener('selectstart', function(e) {
          e.preventDefault();
      })
      

      鼠标事件对象

      鼠标事件对象说明
      e.clientX返回鼠标相对于浏览器窗口可视区的X坐标
      e.clientY返回鼠标相对于浏览器窗口可视区的Y坐标
      e.pageX返回鼠标相对于整个文档页面的X坐标 IE9+支持
      e.pageY返回鼠标相对于整个文档页面的Y坐标 IE9+支持
      e.screenX返回鼠标相对于电脑屏幕的X坐标
      e.screenY返回鼠标相对于电脑屏幕的Y坐标

      常用键盘事件

      键盘事件触发条件
      onkeyup某个键盘按键被松开时触发
      onkeydown被按下时触发
      onkeypress被按下时触发 但不识别功能键 比如ctrl shift 箭头等
      onkeyCode返回该键的ASCII值

      如果使用addEventListener 不需要加 on

      三个事件的执行顺序是: keydown – keypress — keyup (按下–按住–抬起

      keyCode判断用户按下哪个键

          <script>
              // 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
              document.addEventListener('keyup', function(e) {
                  console.log(e.keyCode);
                  // 我们可以利用keycode返回的ASCII码值来判断用户按下了那个键
                  if (e.keyCode === 65) {
                      alert('您按下的a键');
                  } else {
                      alert('您没有按下a键')
                  }
              })
              document.addEventListener('keypress', function(e) {
                  // console.log(e);
                  console.log(e.keyCode);
              })
          </script>
      
      1. onkeydown 和 onkeyup 不区分字母大小写,通过keyCode属性获取到的a 和 A 得到的都是65
      2. onkeypress 区分字母大小写 ,通过keyCode属性获取到的 a 是 97 和 A 得到的是65
      3. 但是在我们实际开发中,我们更多的使用keydown和keyup, 它能识别所有的键(包括功能键)

      4.BOM、JS执行机制、元素偏移量 offset

      BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window

      页面(窗口)加载事件

      第一种——语法:

      window.onload = function(){}
      或者 
      window.addEventListener("load",function(){});
      
      1. 有了 window.onload 就可以把 JS 代码写到页面元素的上方,因为 onload 是等页面内容全部加载完毕,再去执行处理函数。
      2. window.onload 传统注册事件方式 只能写一次,如果有多个,会以最后一个 window.onload 为准。
      3. 如果使用 addEventListener 则没有限制

      第二种——语法:

      document.addEventListener('DOMContentLoaded',function(){})
      

      DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等。

      调整窗口大小事件

      语法

       window.onresize = function(){}
      
       window.addEventListener("resize",function(){});
      

      window.onresize 是调整窗口大小加载事件, 当触发时就调用的处理函数。

      window.innerWidth 当前屏幕的宽度

      定时器

      setTimeout()

       window.setTimeout(回调函数, [延迟的毫秒数]);
      
      1. window 可以省略。
      2. 这个调用函数可以直接写函数,或者写函数名或者采取**字符串‘函数名()’**三种形式。第三种不推荐
      3. 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符。

      清除定时器:

       window.clearTimeout(定时器名字)
      

      setInterval() 闹钟定时器

       window.setInterval(回调函数, [间隔的毫秒数]);
      

      和setTimeout用法类似

      清除定时器:

       window.clearInterval(intervalID);
      

      this指向问题

      1. 全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this也指向window)
      2. 方法调用中谁调用this指向谁
      3. 构造函数中this指向构造函数的实例(通过构造函数new出来的对象)

      location对象

      获取或设置窗体的 URL,并且可以用于解析 URL

      URL 的一般语法格式为:

       protocol://host[:port]/path/[?query]#fragment
      
       http://www.itcast.cn/index.html?name=andy&age=18#link
      

      location 对象的属性

      location 对象属性返回值
      location.href获取或设置整个URL
      location.host返回主机(域名)
      location.port返回端口号
      location.pathname返回路径
      location.search返回参数
      location.hash返回片段 #后面内容 常见于链接 锚点

      location对象的常见方法

      location对象方法返回值
      location.assign()和href一样,可以跳转页面
      location.replace()替换当前页面,因为不记录历史,所以不能后退
      location.reload()重新加载页面,相当于刷新按钮或者F5 如果参数为true 强制刷新

      navigator对象

      navigator 对象包含有关浏览器的信息,它有很多属性,我们最常用的是 userAgent,该属性可以返回由客户机发送服务器的 user-agent 头部的值

      下面前端代码可以判断用户那个终端打开页面,实现跳转

      if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
          window.location.href = "";     //手机
       } else {
          window.location.href = "";     //电脑
       }
      

      history对象

      与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL

      history对象方法作用
      back()后退功能
      forward()前进功能
      go(参数)前进后退功能 参数是1则前进1个页面 参数是-1 后退1个页面

      JS执行机制

      同步:先做一件事情,然后再做另一件事情。他是单线程,一个人依次做多件事情

      异步:是两件事情同时去做,他是多线程,多个人同时做多个事情

      元素偏移量 offset

      offset属性作用
      element.offsetParent返回该元素带有定位的父元素 如果父级都没有定位则返回body
      element.offsetTop返回该元素相对带有定位父元素上方的偏移量
      element.offsetLeft返回该元素相对带有定位父元素左边的偏移量
      element.offsetWidth返回自身padding、边框、内容区的宽度
      element.offsetHeight返回自身padding、边框、内容区的高度

      注意:返回的数值都不带单位

      offset 与 style 区别

      offset:想要获取元素大小位置,用offset更合适

      style:想要给元素更改值,则需要用style改变

      获取鼠标在盒子内的坐标

      1. 我们在盒子内点击,想要得到鼠标距离盒子左右的距离。
      2. 首先得到鼠标在页面中的坐标(e.pageX, e.pageY)
      3. 其次得到盒子在页面中的距离 ( box.offsetLeft, box.offsetTop)
      4. 用鼠标距离页面的坐标减去盒子在页面中的距离,得到 鼠标在盒子内的坐标
      5. 如果想要移动一下鼠标,就要获取最新的坐标,使用鼠标移动
      var box = document.querySelector('.box');
      box.addEventListener('mousemove', function(e) {
      var x = e.pageX - this.offsetLeft;
      var y = e.pageY - this.offsetTop;
      this.innerHTML = 'x坐标是' + x + ' y坐标是' + y;
      })
      

      5.元素可视区 client 、元素滚动 scroll、动画函数封装

      client

      通过 client系列的相关属性可以动态的得到该元素的边框大小、元素大小等

      client系列属性作用
      element.clientTop返回元素上边框的大小
      element.clientLeft返回元素左边框的大小
      element.clientWidth返回自身包括padding、内容区的宽度,不含边框,返回数值不带单位
      element.clientHeight返回自身包括padding、内容区的高度,不含边框,返回数值不带单位

      立即执行函数

      1. (function(){})()
      2. (function(){}())

      创建一个独立的作用域,避免了命名冲突问题

      pageshow

      • 这个事件在页面显示时触发,无论页面是否来自缓存。
      • 在重新加载页面中,pageshow会在load事件触发后触发;
      • 根据事件对象中的persisted来判断是否是缓存中的页面触发的pageshow事件
      • persisted:判断页面是否来自缓存,如果是返回true,如果不是返回false
      • 注意这个事件给window添加

      元素滚动 scroll

      scroll系列属性作用
      element.scrollTop返回被卷去的上侧距离
      element.scrollLeft返回被卷去的左侧距离
      element.scrollWidth返回自身实际的宽度,不含边框
      element.scrollHeight返回自身实际的高度,不含边框

      返回数值均不带单位

      • 当滚动条向下滚动时,页面上面被隐藏掉的高度,我们就称为页面被卷去的头部。
      • 滚动条在滚动时会触发 onscroll事件

      页面被卷去的头部

      可以通过window.pageYOffset 获得 如果是被卷去的左侧window.pageXOffset

      注意,元素被卷去的头部是element.scrollTop , 如果是页面被卷去的头部 则是 window.pageYOffset

      页面被卷去的头部兼容性解决方案

      需要注意的是,获取页面被卷去的头部高度,有兼容性问题,因此通常有如下几种写法:

      1. 声明了 DTD,使用 document.documentElement.scrollTop
      2. 未声明 DTD,使用 document.body.scrollTop
      3. 新方法 window.pageYOffset和 window.pageXOffset,IE9 开始支持
      function getScroll() {
          return {
            left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft||0,
            top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0
          };
       } 
      //使用的时候  getScroll().left
      

      mouseenter 和mouseover的区别

      mouseover 鼠标经过自身盒子会触发,经过子盒子还会触发。mouseenter 只会经过自身盒子触发,因为mouseenter不会冒泡。

      跟mouseenter搭配鼠标离开 mouseleave 同样不会冒泡

      简单动画函数封装

      function animate(obj目标对象, target目标位置){…}

      给不同元素记录不同定时器

      核心原理:利用 JS 是一门动态语言,可以很方便的给当前对象添加属性。

       function animate(obj, target) {
                  // 当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时器
                  // 解决方案就是 让我们元素只有一个定时器执行
                  // 先清除以前的定时器,只保留当前的一个定时器执行
                  clearInterval(obj.timer);
                  obj.timer = setInterval(function() {
                      if (obj.offsetLeft >= target) {
                          // 停止动画 本质是停止定时器
                          clearInterval(obj.timer);
                      }
                      obj.style.left = obj.offsetLeft + 1 + 'px';
      
                  }, 30);
              }
      

      动画函数多个目标值之间移动

      <script>
              // 缓动动画函数封装obj目标对象 target 目标位置
              // 思路:
              // 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。
              // 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长
              // 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
              function animate(obj, target) {
                  // 先清除以前的定时器,只保留当前的一个定时器执行
                  clearInterval(obj.timer);
                  obj.timer = setInterval(function () {
                      // 步长值写到定时器的里面
                      // 把我们步长值改为整数 不要出现小数的问题
                      // var step = Math.ceil((target - obj.offsetLeft) / 10);
                      var step = (target - obj.offsetLeft) / 10;
                      step = step > 0 ? Math.ceil(step) : Math.floor(step);
                      if (obj.offsetLeft == target) {
                          // 停止动画 本质是停止定时器
                          clearInterval(obj.timer);
                      }
                      // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
                      obj.style.left = obj.offsetLeft + step + 'px';
      
                  }, 15);
              }
              var span = document.querySelector('span');
              var btn500 = document.querySelector('.btn500');
              var btn800 = document.querySelector('.btn800');
      
              btn500.addEventListener('click', function () {
                  // 调用函数
                  animate(span, 500);
              })
              btn800.addEventListener('click', function () {
                  // 调用函数
                  animate(span, 800);
              })
                  // 匀速动画 就是 盒子是当前的位置 +  固定的值 10 
                  // 缓动动画就是  盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10)
          </script>
      

      动画完整版代码

       <script>
              // 缓动动画函数封装obj目标对象 target 目标位置
              // 思路:
              // 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。
              // 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长
              // 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
              function animate(obj, target, callback) {
                  // console.log(callback);  callback = function() {}  调用的时候 callback()
      
                  // 先清除以前的定时器,只保留当前的一个定时器执行
                  clearInterval(obj.timer);
                  obj.timer = setInterval(function () {
                      // 步长值写到定时器的里面
                      // 把我们步长值改为整数 不要出现小数的问题
                      // var step = Math.ceil((target - obj.offsetLeft) / 10);
                      var step = (target - obj.offsetLeft) / 10;
                      step = step > 0 ? Math.ceil(step) : Math.floor(step);
                      if (obj.offsetLeft == target) {
                          // 停止动画 本质是停止定时器
                          clearInterval(obj.timer);
                          // 回调函数写到定时器结束里面
                          if (callback) {
                              // 调用函数
                              callback();
                          }
                      }
                      // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
                      obj.style.left = obj.offsetLeft + step + 'px';
      
                  }, 15);
              }
              var span = document.querySelector('span');
              var btn500 = document.querySelector('.btn500');
              var btn800 = document.querySelector('.btn800');
      
              btn500.addEventListener('click', function () {
                  // 调用函数
                  animate(span, 500);
              })
              btn800.addEventListener('click', function () {
                  // 调用函数
                  animate(span, 800, function () {
                      // alert('你好吗');
                      span.style.backgroundColor = 'red';
                  });
              })
                  // 匀速动画 就是 盒子是当前的位置 +  固定的值 10 
                  // 缓动动画就是  盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10)
          </script>
      

      节流阀

      当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发,利用回调函数,添加一个变量来控制,锁住函数和解锁函数

      1. 开始设置一个变量var flag= true;
      2. If(flag){flag = false; do something} 关闭水龙头
      3. 利用回调函数动画执行完毕, flag = true 打开水龙头

      返回顶部

      1. 页面滚动了多少,可以通过 window.pageYOffset 得到
      2. 最后是页面滚动,使用 window.scroll(x,y) 不带单位 直接写数字

      6.移动端和插件的使用、本地存储

      常见的触屏事件

      触屏touch事件说明
      touchstart手指触摸到一个DOM元素时触发
      touchmove手指在一个DOM元素上滑动时触发
      touchend手指从一个DOM元素上移开时触发

      触摸事件对象(TouchEvent)

      TouchEvent 是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等

      触摸列表说明
      touches正在触摸屏幕的所有手指的一个列表
      targetTouches正在触摸当前DOM元素上的手指的一个列表
      changedTouches手指状态发生了改变的列表,从无到有,从有到无的变化

      因为平时我们都是给元素注册触摸事件,所以重点记住 targetTocuhes

      移动端拖动元素

       <script>
              // (1) 触摸元素 touchstart:  获取手指初始坐标,同时获得盒子原来的位置
              // (2) 移动手指 touchmove:  计算手指的滑动距离,并且移动盒子
              // (3) 离开手指 touchend:
              var div = document.querySelector('div');
              var startX = 0; //获取手指初始坐标
              var startY = 0;
              var x = 0; //获得盒子原来的位置
              var y = 0;
              div.addEventListener('touchstart', function(e) {
                  //  获取手指初始坐标
                  startX = e.targetTouches[0].pageX;
                  startY = e.targetTouches[0].pageY;
                  x = this.offsetLeft;
                  y = this.offsetTop;
              });
      
              div.addEventListener('touchmove', function(e) {
                  //  计算手指的移动距离: 手指移动之后的坐标减去手指初始的坐标
                  var moveX = e.targetTouches[0].pageX - startX;
                  var moveY = e.targetTouches[0].pageY - startY;
                  // 移动我们的盒子 盒子原来的位置 + 手指移动的距离
                  this.style.left = x + moveX + 'px';
                  this.style.top = y + moveY + 'px';
                  e.preventDefault(); // 阻止屏幕滚动的默认行为
                  //如果不阻止,当粉色盒子滚出界面之后会出现滚动条
              });
          </script>
      

      注意: 手指移动也会触发滚动屏幕所以这里要阻止默认的屏幕滚动 e.preventDefault();

      transitionend

      监听过渡完成的事件对象

      语法: element.addEventListener(‘transitionend’,函数);

      classList 属性

      返回元素的类名。但是ie10以上版本支持

      添加类:

      element.classList.add(’类名’);

      focus.classList.add('current');
      

      移除类:

      element.classList.remove(’类名’);

      focus.classList.remove('current');
      例:ol.querySelector('.sty').classList.remove('sty');
      

      切换类:

      element.classList.toggle(’类名’); 有这个类名则移除,没有则添加

      focus.classList.toggle('current');
      

      注意:以上方法里面,所有类名都不带点

      click 延时解决方案

      移动端 click 事件会有 300ms 的延时,原因是移动端屏幕双击会缩放(double tap to zoom) 页面。

      解决方案:

      ​ 1. 禁用缩放: 浏览器禁用默认的双击缩放行为并且去掉300ms 的点击延迟。

        <meta name="viewport" content="user-scalable=no">
      

      ​ 2.利用touch事件自己封装这个事件解决300ms 延迟。

      ​ 原理就是:

      ​ 当我们手指触摸屏幕,记录当前触摸时间

      ​ 当我们手指离开屏幕, 用离开的时间减去触摸的时间

      ​ 如果时间小于150ms,并且没有滑动过屏幕, 那么我们就定义为点击

      代码如下:

      //封装tap,解决click 300ms 延时
      function tap (obj, callback) {
              var isMove = false;
              var startTime = 0; // 记录触摸时候的时间变量
              obj.addEventListener('touchstart', function (e) {
                  startTime = Date.now(); // 记录触摸时间
              });
              obj.addEventListener('touchmove', function (e) {
                  isMove = true;  // 看看是否有滑动,有滑动算拖拽,不算点击
              });
              obj.addEventListener('touchend', function (e) {
                  if (!isMove && (Date.now() - startTime) < 150) {  // 如果手指触摸和离开时间小于150ms 算点击
                      callback && callback(); // 执行回调函数
                  }
                  isMove = false;  //  取反 重置
                  startTime = 0;
              });
      }
      //调用  
        tap(div, function(){   // 执行代码  });
      

      ​ 3.使用插件:fastclick 插件解决300ms 延迟

        <script src="fastclick.js"></script>
        <script>
              if ('addEventListener' in document) {
                  document.addEventListener('DOMContentLoaded', function() {
                      FastClick.attach(document.body);
                  }, false);
              }
          </script>
      

      Swiper 插件

      中文官网地址: https://www.swiper.com.cn/

      其他移动端常见插件

      lsuperslide: http://www.superslide2.com/

      l iscroll: https://github.com/cubiq/iscroll

      ​ 1.打开demo实例文件,查看需要引入的相关文件,并且引入

      ​ 2.复制demo实例文件中的结构html,样式css以及js代码

      移动端视频插件

      zy.media.js

      Bootstrap

      Bootstrap JS插件使用步骤:

      1.引入相关js 文件

      2.复制HTML 结构

      3.修改对应样式

      4.修改相应JS 参数

      本地存储

      1、容量较大,sessionStorage约5M、localStorage约20M

      2、只能存储字符串,可以将对象JSON.stringify() 编码后存储

      window.sessionStorage (session:会话)

      1、生命周期为关闭浏览器窗口

      2、在同一个窗口(页面)下数据可以共享

      3、以键值对的形式存储使用

      存储数据:

      sessionStorage.setItem('key', 存的内容)
      

      获取数据:

      sessionStorage.getItem('key')
      

      删除数据:

      sessionStorage.removeItem('key')
      

      清空数据:(所有都清除掉)

      sessionStorage.clear()
      

      window.localStorage

      1、声明周期永久生效,除非手动删除 否则关闭页面也会存在

      2、可以多窗口(页面)共享(同一浏览器可以共享)

      3、以键值对的形式存储使用

      存储数据:

      localStorage.setItem('key', value)
      

      获取数据:

      localStorage.getItem('key')
      

      删除数据:

      localStorage.removeItem('key')
      

      清空数据:(所有都清除掉)

      localStorage.clear()
      

      change事件

      当选框发生改变的时候可以使用change事件

      六.jQuery

      1.选择器、样式操作、效果

      jQuery 对象本质是: 利用$对DOM 对象包装后产生的对象(伪数组形式存储)

      注意:

      只有 jQuery 对象才能使用 jQuery 方法,DOM 对象则使用原生的 JavaScirpt 方法。

      jQuery 的下载**

      jQuery的官网地址: https://jquery.com/,官网即可下载最新版本。

      各个版本的下载:https://code.jquery.com/

      jQuery的入口函数

      ​ jQuery中常见的两种入口函数:

      // 第一种: 简单易用。
      $(function () {   
          ...  // 此处是页面 DOM 加载完成的入口
      }) ; 
      
      // 第二种: 繁琐,但是也可以实现
      $(document).ready(function(){
         ...  //  此处是页面DOM加载完成的入口
      });
      

      相当于原生 js 中的 DOMContentLoaded

      jQuery 对象和 DOM 对象转换

      // 1.DOM对象转换成jQuery对象,方法只有一种
      var box = document.getElementById('box');  // 获取DOM对象
      var jQueryObject = $(box);  // 把DOM对象转换为 jQuery 对象
      
      // 2.jQuery 对象转换为 DOM 对象有两种方法:
      //   2.1 jQuery对象[索引值]
      var domObject1 = $('div')[0]
      
      //   2.2 jQuery对象.get(索引值)
      var domObject2 = $('div').get(0)
       
      

      总结:实际开发比较常用的是把DOM对象转换为jQuery对象

      jQuery 选择器

      $("选择器")   //  里面选择器直接写 CSS 选择器即可,但是要加引号 和CSS选择器写法一致
      

      筛选选择器

      语法用法描述
      :first$(‘li:first’)获取第一个li元素
      :last$(‘li:last’)获取最后一个li元素
      :eq(index)$(‘li:eq(2)’)获取li元素中索引号为2的元素,index从0开始
      :odd$(‘li:odd’)获取li元素中索引号为奇数的元素
      :even$(‘li:even’)获取li元素中索引号为偶数的元素

      筛选方法

      语法用法说明
      parent()$(‘li’).parent();查找父级
      children(‘选择器’)$(“ul”).children(“li”);查找最近一级的亲儿子 相当于$(“ul>li”)
      find(‘选择器’)$(“ul”).find(“li”);相当于$(“ul li”) 和后代选择器一样
      siblings(‘选择器’)$(".first").siblings(“li”);查找兄弟节点,不包括自身
      nextAll([expr])$(".first").nextAll();查找当前元素之后所有的兄弟元素
      prevAll([expr])$(".first").prevAll();查找当前元素之前所有的兄弟元素
      hasClass(class)$(“div”).hasClass("protected"0;检查当前的元素是否含有某个特定的类,如果有 返回true
      eq(index)$(“li”).eq(2);相当于$(‘li:eq(2)’),index是从0开始的

      jQuery样式操作

      排他思想

      // 想要多选一的效果,排他思想:当前元素设置样式,其余的兄弟元素清除样式。
      $(this).css(“color”,”red”);
      $(this).siblings().css(“color”,””);
      

      隐式迭代

      // 遍历内部 DOM 元素(伪数组形式存储)的过程就叫做隐式迭代。
      // 简单理解:给匹配到的所有元素进行循环遍历,执行相应的方法,而不用我们再进行循环,简化我们的操作,方便我们调用。
      $('div').hide();  // 页面中所有的div全部隐藏,不用循环操作
      
      
      // 以前的js是不允许对于一组对象之间操作的,只能对一个元素对象进行操作
      var divs = document.getElementsByTagName('div');
      divs.style.backgroundColor = 'red'; // 错误
      divs[0].style.backgroundColor = 'red'; // 正确
      

      链式编程

      // 链式编程是为了节省代码量,看起来更优雅。
      //原代码
      $(this).css('color', 'red');
      $(this).sibling().css('color', ''); 
      //链式编程的代码
      $(this).css('color', 'red').sibling().css('color', ''); 
      
      //jq的操作方法: css(),hide(),show()等等,会将调用者返回
      //jq的筛选方法,会将筛选完的对象返回。 非筛选方法(操作方法),会将调用者(jq对象)返回
      

      jQuery 得到当前元素索引号

      $(this).index();

      jQuery弹窗(类似alert)

      var isC = confirm('您确定要退出吗') //点击后返回布尔值

      jQuery操作 css 方法

      // 1.参数只写属性名,则是返回属性值
      var strColor = $(this).css('color');
      
      // 2.  参数是属性名,属性值,逗号分隔,是设置一组样式,属性必须加引号,值如果是数字可以不用跟单位和引号
      $(this).css('color'', 'red');
      
      // 3.  参数可以是对象形式,方便设置多组样式。属性名和属性值用冒号隔开, 属性可以不用加引号
      $(this).css({ "color":"white","font-size":"20px"});
      

      jQuery设置类样式

      // 1.添加类
      $("div").addClass("current");  // className,classList
      
      // 2.删除类
      $("div").removeClass("current");
      
      // 3.切换类  没有就添上  有就移除
      $("div").toggleClass("current");
      

      原生 JS 中 className 会覆盖元素原先里面的类名,jQuery 里面类操作只是对指定类进行操作,不影响原先的类名

      jQuery 效果

      显示、隐藏、二者切换

      显示

      语法: show( [ speed ,[easing],[fn] ] ) 参数都可以省略

      1.speed: 按照某种速度显示,默认normal,还有slow、fast,要带引号,也可直接设置毫秒数(不带单位)

      2.easing: 用来指定切换效果,默认swing,还有linear,要带引号

      3.fn: 回调函数,在动画完成时执行的函数,每个元素执行一次

      隐藏

      语法: hide( [ speed ,[easing],[fn] ] ) 参数都可以省略

      1.speed: 按照某种速度显示,默认normal,还有slow、fast,要带引号,也可直接设置毫秒数(不带单位)

      2.easing: 用来指定切换效果,默认swing,还有linear,要带引号

      3.fn: 回调函数,在动画完成时执行的函数,每个元素执行一次

      切换

      语法: toggle( [ speed ,[easing],[fn] ] ) 参数都可以省略

      1.speed: 按照某种速度显示,默认normal,还有slow、fast,要带引号,也可直接设置毫秒数(不带单位)

      2.easing: 用来指定切换效果,默认swing,还有linear,要带引号

      3.fn: 回调函数,在动画完成时执行的函数,每个元素执行一次

      滑动

      下拉滑动

      语法: slideDown( [ speed ,[easing],[fn] ] ) 参数都可以省略

      1.speed: 按照某种速度显示,默认normal,还有slow、fast,要带引号,也可直接设置毫秒数(不带单位)

      2.easing: 用来指定切换效果,默认swing,还有linear,要带引号

      3.fn: 回调函数,在动画完成时执行的函数,每个元素执行一次

      上拉滑动

      语法: slideUp( [ speed ,[easing],[fn] ] ) 参数都可以省略

      1.speed: 按照某种速度显示,默认normal,还有slow、fast,要带引号,也可直接设置毫秒数(不带单位)

      2.easing: 用来指定切换效果,默认swing,还有linear,要带引号

      3.fn: 回调函数,在动画完成时执行的函数,每个元素执行一次

      滑动切换

      语法: slideToggle( [ speed ,[easing],[fn] ] ) 参数都可以省略

      1.speed: 按照某种速度显示,默认normal,还有slow、fast,要带引号,也可直接设置毫秒数(不带单位)

      2.easing: 用来指定切换效果,默认swing,还有linear,要带引号

      3.fn: 回调函数,在动画完成时执行的函数,每个元素执行一次

      淡入淡出 (透明度动画)

      淡入

      语法: fadeIn( [ speed ,[easing],[fn] ] ) 参数都可以省略

      1.speed: 按照某种速度显示,默认normal,还有slow、fast,要带引号,也可直接设置毫秒数(不带单位)

      2.easing: 用来指定切换效果,默认swing,还有linear,要带引号

      3.fn: 回调函数,在动画完成时执行的函数,每个元素执行一次

      淡出

      语法: fadeOut( [ speed ,[easing],[fn] ] ) 参数都可以省略

      1.speed: 按照某种速度显示,默认normal,还有slow、fast,要带引号,也可直接设置毫秒数(不带单位)

      2.easing: 用来指定切换效果,默认swing,还有linear,要带引号

      3.fn: 回调函数,在动画完成时执行的函数,每个元素执行一次

      淡入淡出切换

      语法: fadeToggle( [ speed ,[easing],[fn] ] ) 参数都可以省略

      1.speed: 按照某种速度显示,默认normal,还有slow、fast,要带引号,也可直接设置毫秒数(不带单位)

      2.easing: 用来指定切换效果,默认swing,还有linear,要带引号

      3.fn: 回调函数,在动画完成时执行的函数,每个元素执行一次

      修改透明度

      语法: fadeTo( [ speed , opacity ,[easing],[fn] ] ) 参数都可以省略

      1. opacity 透明度,必须写,取值0~1之间
      2. speed: 必须写 按照某种速度显示,默认normal,还有slow、fast,要带引号,也可直接设置毫秒数(不带单位)
      3. easing: 用来指定切换效果,默认swing,还有linear,要带引号
      4. fn: 回调函数,在动画完成时执行的函数,每个元素执行一次
      <body>
          <button>淡入效果</button>
          <button>淡出效果</button>
          <button>淡入淡出切换</button>
          <button>修改透明度</button>
          <div></div>
          <script>
              $(function() {
                  $("button").eq(0).click(function() {
                      // 淡入 fadeIn()
                      $("div").fadeIn(1000);
                  })
                  $("button").eq(1).click(function() {
                      // 淡出 fadeOut()
                      $("div").fadeOut(1000);
                  })
                  $("button").eq(2).click(function() {
                      // 淡入淡出切换 fadeToggle()
                      $("div").fadeToggle(1000);
                  });
                  $("button").eq(3).click(function() {
                      //  修改透明度 fadeTo() 这个速度和透明度要必须写
                      $("div").fadeTo(1000, 0.5);
                  });
              });
          </script>
      </body>
      

      自定义动画

      语法:animate( params, [speed ] , [easing] , [fn] )

      1.params:想要改变的样式属性,以对象形式传递,必须写

      2.speed: 按照某种速度显示,默认normal,还有slow、fast,要带引号,也可直接设置毫秒数(不带单位)

      3.easing: 用来指定切换效果,默认swing,还有linear,要带引号

      4.fn: 回调函数,在动画完成时执行的函数,每个元素执行一次

      <body>
          <button>动起来</button>
          <div></div>
          <script>
              $(function() {
                  $("button").click(function() {
                      $("div").animate({
                          left: 500,
                          top: 300,
                          opacity: .4,
                          width: 500
                      }, 500);
                  })
              })
          </script>
      </body>
      

      停止动画排队

      动画或者效果一旦触发就会执行,如果多次触发,就造成多个动画或者效果排队执行

      停止动画排队的方法为:stop() ;

      • stop() 方法用于停止动画或效果。
      • stop() 写到动画或者效果的前面, 相当于停止结束上一次的动画。

      总结: 每次使用动画之前,先调用 stop() ,在调用动画。

      事件切换

      hover([over,]out)     // 其中over和out为两个函数
      
      • over:鼠标移到元素上要触发的函数(相当于mouseenter)
      • out:鼠标移出元素要触发的函数(相当于mouseleave)
      • 如果只写一个函数,则鼠标经过和离开都会触发它

      2.属性、元素、尺寸、位置操作

      jQuery 属性操作

      获取和设置元素固有属性值 prop()

      1.获取元素固有属性: element.prop(‘属性名’);

      2.设置元素固有属性: element.prop(‘属性名’,‘属性值’);

      ​ 注意:prop() 除了普通属性操作,更适合操作表单属性:disabled / checked / selected 等。

      获取和设置元素自定义属性值 attr()

      1.获取元素自定义属性: element.attr(‘属性名’);

      2.设置元素自定义属性: element.attr(‘属性名’,‘属性值’);

      数据缓存 data()

      1.获取数据缓存: element.date(‘数据名’);

      2.设置数据缓存: element.date(‘数据名’,‘数据值’);

      选择器 :checked

      例:console.log($(".j-checkbox:checked").length);

      jQuery 文本属性值

      常见操作有三种:html() / text() / val() ; 分别对应JS中的 innerHTML 、innerText 和 value 属性

      普通元素内容html()

      1.html() //获取元素内容

      2.html(‘内容’) //设置元素内容

      普通元素文本内容text()

      1.text() //获取元素的文本内容

      2.text(‘内容’) //设置元素的文本内容

      表单的值val()

      1.val() //获取表单的值

      2.val(‘内容’) //设置表单的值

      注意:html() 可识别标签,text() 不识别标签

      选择器parents

      parents(‘选择器’) 可以返回指定祖先元素

      保留几位小数

      num.toFixed(位数)

      jQuery 元素操作

      遍历元素

      1. $(‘选择器’).each(function ( index , ele ) {…;} ) index是索引号,ele是每个DOM元素对象
      2. $.each( object , function ( index , ele ) { …; } )

      ​注意:此方法用于遍历 jQuery 对象中的每一项,回调函数中元素为 DOM 对象,想要使用 jQuery 方法需要转换。

      演示代码

      <body>
          <div>1</div>
          <div>2</div>
          <div>3</div>
          <script>
              $(function() {
                  // 如果针对于同一类元素做不同操作,需要用到遍历元素(类似for,但是比for强大)
                  var sum = 0;
                  var arr = ["red", "green", "blue"];
                  // 1. each() 方法遍历元素 
                  $("div").each(function(i, domEle) {
                      // 回调函数第一个参数一定是索引号  可以自己指定索引号号名称
                      // console.log(i);
                      // 回调函数第二个参数一定是 dom 元素对象,也是自己命名
                      // console.log(domEle);  // 使用jQuery方法需要转换 $(domEle)
                      $(domEle).css("color", arr[i]);
                      sum += parseInt($(domEle).text());
                  })
                  console.log(sum);
                  // 2. $.each() 方法遍历元素 主要用于遍历数据,处理数据
                  // $.each($("div"), function(i, ele) {
                  //     console.log(i);
                  //     console.log(ele);
                  // });
                  // $.each(arr, function(i, ele) {
                  //     console.log(i);
                  //     console.log(ele);
                  // })
                  $.each({
                      name: "andy",
                      age: 18
                  }, function(i, ele) {
                      console.log(i); // 输出的是 name age 属性名
                      console.log(ele); // 输出的是 andy  18 属性值
                  })
              })
          </script>
      </body>
      

      创建、添加、删除

      1.创建

      $(’

      • ')

        2.内部添加

        element.append(’ 内容 ') 把内容放入匹配元素内部最后面,类似于appendChild

        element.prepend(’ 内容 ') 把内容放入匹配元素内部最前面,类似于

        3.外部添加

        element.after(’ 内容 ') //把内容放入目标元素后面

        element.before(’ 内容 ') //把内容放入目标元素前面

        4.删除

        element.remove() //删除匹配的元素(自身)

        element.empty() //删除匹配的元素集合中所有的子节点

        element.html(’’) //清空匹配的元素内容

        jQuery 尺寸、位置操作

        尺寸操作

        语法用法
        width()/height()取得匹配元素宽度或高度,只算width/height
        innerWidth()/innerHeight()取得匹配元素宽度或高度,包含padding
        outWidth()/outHeight()取得匹配元素宽度或高度,包含paddin、border
        outWidth(true)/outHeight(true)取得匹配元素宽度或高度,包含paddin、border、margin

        如果参数为数字,则是修改相应值

        jQuery 位置操作

        jQuery的位置操作主要有三个: offset()、position()、scrollTop()/scrollLeft()

        1.offset()设置或获取元素偏移

        和父亲没有关系,是相对于文档的偏移坐标

        该方法有2个属性left、top。offset().top/left 用于获取距离文档顶部/左侧的距离

        可以设置元素的偏移: offset( { top:10,left:10 } )

        2.position()获取元素偏移

        和父亲有关系,是相对于父亲的偏移坐标,如果父亲都没有定位,则以文档为准

        该方法有2个属性left、top。offset().top/left 用于获取距离文档顶部/左侧的距离

        该方法只能获取数据,不可以进行设置

        3.scrollTop()/scrollLeft()设置或获取元素被卷去的头部或左侧

        不加参数是获取,加参数则是设置被卷去的头部,参数不带单位

        代码演示

        <body>
            <div class="father">
                <div class="son"></div>
            </div>
                
            <div class="back">返回顶部</div>
            <div class="container"></div>
           
            <script>
                $(function() {
                    // 1. 获取设置距离文档的位置(偏移) offset
                    console.log($(".son").offset());
                    console.log($(".son").offset().top);
                    // $(".son").offset({
                    //     top: 200,
                    //     left: 200
                    // });
              
                    // 2. 获取距离带有定位父级位置(偏移) position   如果没有带有定位的父级,则以文档为准
                    // 这个方法只能获取不能设置偏移
                    console.log($(".son").position());
                    // $(".son").position({
                    //     top: 200,
                    //     left: 200
                    // });
              
              		// 3. 被卷去的头部
              		$(document).scrollTop(100);
                    // 被卷去的头部 scrollTop()  / 被卷去的左侧 scrollLeft()
                    // 页面滚动事件
                    var boxTop = $(".container").offset().top;
                    $(window).scroll(function() {
                        // console.log(11);
                        console.log($(document).scrollTop());
                        if ($(document).scrollTop() >= boxTop) {
                            $(".back").fadeIn();
                        } else {
                            $(".back").fadeOut();
                        }
                    });
                    // 返回顶部
                    $(".back").click(function() {
                        // $(document).scrollTop(0);
                        $("body, html").stop().animate({
                            scrollTop: 0
                        });
                        // $(document).stop().animate({
                        //     scrollTop: 0
                        // }); 不能是文档而是 html和body元素做动画
                    })
                })
            </script>
        </body>
        

        页面滚动事件

        $(window).scroll( function () {…} )

        3.事件、插件

        jQuery 事件处理

        on() 绑定事件

        语法: element.on( ‘事件类型’, ’ 元素的子元素选择器 ’ , fn(){…} );

        1.可绑定多个事件

        例:

        $(' 选择器').on( { 
        	click : function () {},
        	mouseover: function () {},
        	.......  });
        

        2.可以进行事件委派操作,把需要加给子元素身上的事件绑定在父元素身上

        $(' ul').on( 'click','li',function () { ...... }  );
        

        3.动态创建的元素,用click()这种没法绑定事件,on()可以给动态生成的元素绑定事件,通过事件委托绑定的事件,可以对未来元素生效

        off() 解绑事件

        off()方法可以移除通过on()方法添加的事件

        1.$(’ p ').off() //解绑p元素所有事件

        2.$(’ p ‘).off(’ click ') //解绑p元素上面的点击事件

        3.$(’ ul ‘).off(’ click ‘,’ li’) //解绑事件委托

        只触发一次的事件

        element.one();

        trigger() 自动触发事件

        1.element.click()

        2.element.trigger(‘事件类型’)

        3.element.triggerHandler(‘事件类型’) //这一种不会触发元素的默认行为 而上面的会

        jQuery 事件对象

        element.on( ‘事件类型’, ’ 元素的子元素选择器 ’ , fn( e ){…} );

        阻止默认行为:e.preventDefault()或者return false

        阻止冒泡:e.stopPropagation()

        jQuery 插件

        jQuery 插件常用的网站:

        1. jQuery 插件库 http://www.jq22.com/
        2. jQuery 之家 http://www.htmleaf.com/

        插件的使用三点: 1. 引入css. 2.引入JS 3.引入html。 (有的简单插件只需引入html和js,甚至有的只需引入js)

        七.JS高级

        1.对象与类

        对象

        对象是由属性和方法组成的:是一个无序键值对的集合,指的是一个具体的事物

        属性:事物的特征,在对象中用属性来表示(常用名词)

        方法:事物的行为,在对象中用方法来表示(常用动词)

        类抽象了对象的公共部分,它泛指某一大类(class)对象特指某一个, 通过类实例化一个具体的对象

        创建类

        语法:
        class name{
        constructor( ){ ..... }
        .....
        }
        var 变量名 = new name();
        

        constructor构造函数

        可以接受传递过来的参数,同时返回实例对象 ,只要 new 生成实例时,就会自动调用这个函数, 如果我们不写这个 函数,类也会自动生成这个函数

        类创建添加属性和方法

         // 1. 创建类 class  创建一个 明星类
                class Star {
                    // 类的共有属性放到 constructor 里面
                    constructor(uname, age) {
                        this.uname = uname;
                        this.age = age;
                    }
                    sing(song) {
                        // console.log('我唱歌');
                        console.log(this.uname + song);
        
                    }
                }
        
                // 2. 利用类创建对象 new
                var ldh = new Star('刘德华', 18);
                var zxy = new Star('张学友', 20);
                console.log(ldh);
                console.log(zxy);
                // (1) 我们类里面所有的函数不需要写function 
                //(2) 多个函数方法之间不需要添加逗号分隔
                ldh.sing('冰雨');
                zxy.sing('李香兰')
        

        类的继承

        class son extends father { … }

         // 1. 类的继承
                // class Father {
                //     constructor() {
        
                //     }
                //     money() {
                //         console.log(100);
        
                //     }
                // }
                // class Son extends Father {
        
                // }
                // var son = new Son();
                // son.money();
                class Father {
                    constructor(x, y) {
                        this.x = x;
                        this.y = y;
                    }
                    sum() {
                        console.log(this.x + this.y);
        
                    }
                }
                class Son extends Father {
                    constructor(x, y) {
                        super(x, y); //调用了父类中的构造函数
                    }
                }
                var son = new Son(1, 2);
                var son1 = new Son(11, 22);
                son.sum();
                son1.sum();
        

        关键字super

        用于访问和调用对象父类上的函数,必须在子类this之前调用

         // super 关键字调用父类普通函数
                class Father {
                    say() {
                        return '我是爸爸';
                    }
                }
                class Son extends Father {
                    say() {
                        // console.log('我是儿子');
                        console.log(super.say() + '的儿子');
                        // super.say() 就是调用父类中的普通函数 say()
                    }
                }
                var son = new Son();
                son.say();
                // 继承中的属性或者方法查找原则: 就近原则
                // 1. 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
                // 2. 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)
                // 3.如果子类想要继承父类的方法,同时在自己内部扩展自己的方法,利用super 调用 父类的构造函数,super 必须在子类this之前调用
        

        this的指向

        1. constructor中的this指向的是new出来的实例对象
        2. 自定义的方法,一般也指向的new出来的实例对象
        3. 绑定事件之后this指向的就是触发事件的事件源

        insertAdjacentHTML( ‘position’ , text)

        可以直接把字符串格式添加到父元素中,和element.append(‘内容’)和element.prepend(‘内容’)类似

        position插入的位置:

        1.beforebegin: 元素自身前面 2.afterend: 元素自身后面

        3.afterbegin: 元素内部第一个子节点之前 4.beforeend: 元素内部最后一个子节点之后

        text: 插入的内容

        鼠标双击事件

        element.ondblclick 但双击会默认选中文字 解决方法插入下面代码:

         // 双击禁止选定文字
             window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
        

        双击文本框让文字内容处于选中状态

        input.select();

        2.构造函数和原理、继承、新增方法

        构造函数和原型

        静态成员和实例成员

        实例成员 :构造函数内部通过this添加的成员

        静态成员:在构造函数本身上添加的成员 比如:构造函数名.静态成员名 = ’ 内容 ';

        ,静态成员只能 通过构造函数来访问 比如:构造函数名.静态成员名

        构造函数原型prototype

        构造函数通过原型分配的函数是所有对象所共享的,每一个构造函数都有一个prototype 属性,指向另一个对象。这个 prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有

        可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可 以共享这些方法

        对象原型

        对象都会有一个属性 _ _ proto _ _ 指向构造函数的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 _ _ proto_ _ 原型的存在

        _ _ proto_ _对象原型和原型对象 prototype 是等价的

        _ _ proto_ _对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是 它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype

        constructor构造函数

        对象原型( _ _ proto_ _)和构造函数(prototype)原型对象里面都有一个属性 constructor 属性 ,constructor 我们称为构造函数,因为它指回构造函数本身。

        constructor 主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来 的构造函数。

        一般情况下,对象的方法都在构造函数的原型对象中设置。如果有多个对象的方法,我们可 以给原型对象采取对象形式赋值,但是这样就会覆盖构造函数原型对象原来的内容,这样修 改后的原型对象 constructor 就不再指向当前构造函数了。此时,我们可以在修改后的 原型对象中,添加一个 constructor 指向原来的构造函数

        原型链

        ①ldh 对象实例 ——(ldh._ _ proto_ _ )——>

        ②Str原型对象 prototype ——(prototype. _ _ proto_ _ )——>

        ③ object原型对象prototype ——(prototype. _ _ proto_ _ )——>

        ④null

        构造函数实例和原型对象三角关系

        ①ldh 对象实例 ——(ldh._ _ proto_ _ )——>

        ②Str原型对象 prototype ——(star.prototype.constructor)——>

        ③构造函数 ——>①

        ③构造函数 ——( star.prototype )——> ② Str原型对象 prototype

        原型对象中this指向

        构造函数中的this和原型对象的this,都指向我们new出来的实例对象

        继承

        call()

        语法:函数名.call( thisArg, arg1 , arg2…)

        thisArg:当前调用函数this的指向对象

        arg1 , arg2…:传递的其他参数

        子构造函数继承父构造函数中的属性借用原型对象继承方法

         <script>
                // 借用父构造函数继承属性
                // 1. 父构造函数
                function Father(uname, age) {
                    // this 指向父构造函数的对象实例
                    this.uname = uname;
                    this.age = age;
                }
                Father.prototype.money = function() {
                    console.log(100000);
        
                };
                // 2 .子构造函数 
                function Son(uname, age, score) {
                    // this 指向子构造函数的对象实例
                    Father.call(this, uname, age);
                    this.score = score;
                }
                // Son.prototype = Father.prototype;  这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
                Son.prototype = new Father();
                // 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
                Son.prototype.constructor = Son;
                // 这个是子构造函数专门的方法
                Son.prototype.exam = function() {
                    console.log('孩子要考试');
        
                }
                var son = new Son('刘德华', 18, 100);
                console.log(son);
                console.log(Father.prototype);
                console.log(Son.prototype.constructor);
            </script>
        
        

        ES5新增方法

        forEach遍历数组

        arr.forEach(function(value, index, array) {
        //参数一是:数组元素
        //参数二是:数组元素的索引
        //参数三是:当前的整个数组  })
        //相当于数组遍历的 for循环 没有返回值
        

        filter过滤数组

        var arr = [1,2,3,4,5];
        arr.filter(function(value, index, array) {
        //参数一是:数组元素
        //参数二是:数组元素的索引
        //参数三是:当前的整个数组
          	return value <=2;
        })
        console.log(newArr);//[1,2] //返回值是一个新数组
        

        some查找数组

        some 查找数组中是否有满足条件的元素
        var arr = [10, 30, 4];
        var flag = arr.some(function(value,index,array) {
        //参数一是:数组元素
        //参数二是:数组元素的索引
        //参数三是:当前的整个数组
        	return value < 3;   }); 
        console.log(flag);//false返回值是布尔值,只要查找到满足条件的一个元素就立马终止循环
        

        some和forEach区别

        1.如果查询数组中唯一的元素, 用some方法更合适,在some 里面 遇到 return true 就 是终止遍历 迭代效率更高

        2.在forEach 里面 return 不会终止迭代

        去除字符串两端的空格

        str.trim()

        获取对象的属性名

        Object.keys(对象名) //获取到当前对象中的属性名 ,返回值是一个数组

        Object.defineProperty设置或修改对象中的属性

        Object.defineProperty(对象名,'修改或新增的属性名',{
        		value:修改或新增的属性的值,
        		writable:true/false,//如果值为false 不允许修改这个属性值          					enumerable: false,//enumerable 如果值为false 则不允许遍历                  configurable: false  //configurable 如果为false 则不允许删除这个属性  属性是否可以被删除或是否可以再次修改特性 }) 
        

        3.this、严格模式、高阶函数、闭包、递归、正则表达式

        函数内部的this指向

        调用方式this指向
        普通函数调用window
        构造函数调用实例对象 原型对象里面的方法也指向实例对象
        对象方法调用该方法所属对象
        事件绑定方法绑定事件对象
        window
        window

        改变函数内部 this 指向

        1.call()方法

        语法:函数名.call( thisArg, arg1 , arg2…)

        thisArg:当前调用函数this的指向对象

        arg1 , arg2…:传递的其他参数

        2.apply()方法

        语法:fun.apply( thisArg, [argsArray] )

        thisArg: 在fun函数运行时指定的this值

        argsArray: 传递的值,为数组形式

        3.bind()方法

        语法:fun.bind( thisArg, arg1,arg2… ) //不会调用函数,但能改变函数内部this指向

        thisArg: 在fun函数运行时指定的this值

        arg1 , arg2…:传递的其他参数

        返回由指定的this值和初始化参数改造的原函数拷贝

        三者的异同

        共同点 : 都可以改变this指向

        不同点: 1.call 和 apply 会调用函数, 并且改变函数内部this指向;

        1. call 和 apply传递的参数不一样,call传递参数使用逗号隔开,apply使用数组传递
        2. 3.bind 不会调用函数, 可以改变函数内部this指向.

        开启严格模式

        在所有语句或者函数内部最前面添加 ’ use strict ';

        高阶函数

        高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。

        闭包

        闭包(closure)指有权访问另一个函数作用域中变量的函数。简单理解就是 ,一个作 域可以访问另外一个函数内部的局部变量。

        代码示例:
          <script>
          		//3秒后打印li的内容
                // var lis = document.querySelectorAll('li');
                // for (var i = 0; i < lis.length; i++) {
                //     (function(i) {
                //         setTimeout(function() {
                //             console.log(lis[i].innerHTML);
        
                //         }, 3000)
                //     })(i);
                // }
        
                // 计算打车价格
                var car = (function() {
                    var price = 5;
                    var begin = 13;
                    return {
                        price: function(n) {
                            if (n <= 3) {
                                return begin;
                            } else {
                                return (n - 3) * price + begin;
                            }
                        }
                    }
                })();
                console.log(car.price(5));
            </script>
        

        递归

        如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。简单理解:函 数内部自己调用自己, 这个函数就是递归函数

        代码示例:
         <script>
         		//利用递归求斐波那契数列
                function fn(n) {
                    if (n == 1 || n == 2) {
                        return 1;
                    }
                    return fn(n - 1) + fn(n - 2);
                }
                console.log(fn(6));
            </script>
        

        正则表达式的创建

        var rg = /123/;
        

        正则表达式测试

        var rg = /123/; 
        console.log(rg.test(123));//匹配字符中是否出现123  出现结果为true console.log(rg.test('abc'));//匹配字符中是否出现123 未出现结果为false
        

        边界符

        1.^:表示匹配行首的文本(以谁开始)

        2.$:表示匹配行尾的文本(以谁结束)

        如果 ^和 $ 在一起,表示必须是精确匹配。

        var rg = /abc/; // 正则表达式里面不需要加引号 不管是数字型还是字符串型 
        // /abc/ 只要包含有abc这个字符串返回的都是true 
        console.log(rg.test('abc')); 
        console.log(rg.test('abcd')); 
        console.log(rg.test('aabcd')); 
        console.log('‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐'); 
        var reg = /^abc/; console.log(reg.test('abc')); // true console.log(reg.test('abcd')); // true
        console.log(reg.test('aabcd')); // false
        console.log('‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐');
        var reg1 = /^abc$/; // 精确匹配 要求必须是 abc字符串才符合规范 console.log(reg1.test('abc')); // true
        console.log(reg1.test('abcd')); // false
        console.log(reg1.test('aabcd')); // false
        console.log(reg1.test('abcabc')); // false
        

        字符类

        字符类表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可供选择的字符 都放在方括号内。

        [ ]方括号

        表示有一系列字符可供选择,只要匹配其中一个就可以了

        var rg = /[abc]/; // 只要包含有a 或者 包含有b 或者包含有c 都返回为true console.log(rg.test('andy'));//true
        console.log(rg.test('baby'));//true
        console.log(rg.test('color'));//true
        console.log(rg.test('red'));//false
        var rg1 = /^[abc]$/; // 三选一 只有是a 或者是 b  或者是c 这三个字母才返回  true console.log(rg1.test('aa'));//false
        console.log(rg1.test('a'));//true
        console.log(rg1.test('b'));//true
        console.log(rg1.test('c'));//true
        console.log(rg1.test('abc'));//true ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐var reg = /^[a‐z]$/ //26个英文字母任何一个字母返回 true  ‐ 表示的是a 到z 的范 围   console.log(reg.test('a'));//true
        console.log(reg.test('z'));//true
        console.log(reg.test('A'));//false ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
        //字符组合
        var reg1 = /^[a‐zA‐Z0‐9]$/; // 26个英文字母(大写和小写都可以)任何一个字母返回  true   ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
        //取反 方括号内部加上 ^ 表示取反,只要包含方括号内的字符,都返回 false 。 var reg2 = /^[^a‐zA‐Z0‐9]$/;
        console.log(reg2.test('a'));//false
        console.log(reg2.test('B'));//false
        console.log(reg2.test(8));//false
        console.log(reg2.test('!'));//true
        

        量词符

        量词说明
        *重复>=0次
        +重复>=1次
        ?重复0次或1次
        {n}重复n次
        {n,}重复>=n次
        {n,m}重复n到m次

        预定义类

        预定类说明
        \d匹配0-9之间任一数字,相当于[0-9]
        \D匹配所有0-9以外的字符,相当于[ ^0-9]
        \w匹配任意的字母、数字和下划线, 相当于[A-Za-z0-9]
        \W匹配所有字母、数字和下划线以外的字符, 相当于[ ^A-Za-z0-9]
        \s匹配空格(包括换行符、制表符、空格符等),相当于[\t\r\n\v\f]
        \S匹配非空格的字符,相当于[ ^\t\r\n\v\f]

        正则替换replace

        replace() 方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正 则表达式

        stringObject.replace( / 表达式 / switch, replacement )

        表达式 :被替换的字符串或正则表达式

        switch:g–全局匹配; i–忽略大小写; gi–全局匹配+忽略大小写

        replacement:替换为的字符串

        返回值是一个替换完毕的新字符串

        4.ES6语法

        let

        1.使用let关键字声明的变量才具有块级作用域,使用var声明的变量不具备块级作用 域特性

        2.使用let关键字声明的变量没有变量提升,要先声明才能使用

        const

        用来声明常量,常量就是值(内存地址)不能变化的量

        1.具有块级作用域 ,声明 const时候必须要给定值

        2.如果是常量不能重新进行赋值,如果是基本数据类型,不能更改值,如果是复杂数据 类型,不能更改地址值

        解构赋值

        ES6中允许从数组中提取值,按照对应位置,对变量赋值,对象也可以实现解构

        1.解构赋值就是把数据结构分解,然后给变量进行赋值

        2.如果结构不成功,变量跟数值个数不匹配的时候,变量的值为undefined

        3.数组解构用中括号包裹,多个变量用逗号隔开,对象解构用花括号包裹,多个变量用 逗号隔开

        箭头函数

        () => {} //():代表是函数; =>:必须要的符号,指向哪一个代码块;{}:函数体
        const fn = () => {}//代表把一个函数赋值给fn
        

        1.函数体中只有一句代码,且代码的执行结果就是返回值,可以省略大括号

        2.如果形参只有一个,可以省略小括号

        3.箭头函数不绑定this关键字,箭头函数中的this,指向的是函数定义位置的上下文this

        剩余参数

        function sum (first, ...args) {
        	console.log(first); // 10      
        	console.log(args); // [20, 30]   
        }  
        sum(10, 20, 30);
        

        Array 的扩展方法

        扩展运算符 //扩展运算符可以将数组或者对象转为用逗号分隔的参数序列

        let ary = [1, 2, 3];
        ...ary  // 1, 2, 3
        console.log(...ary);    // 1 2 3,相当于下面的代码
        console.log(1,2,3)
        

        构造函数方法:Array.from()

        将伪数组或可遍历对象转换为真正的数组

        //定义一个集合
        let arrayLike = {
        	'0': 'a',    
        	'1': 'b',    
        	'2': 'c',    
        	length: 3 
        }; 
        //转成数组
        let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
        

        该方法还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理, 将处理后的值放入返回的数组

        find()

        用于找出第一个符合条件的数组成员,如果没有找到返回undefined

        let ary = [{
        	id: 1,
        	name: '张三'
        }, {
        	id: 2,
        	name: '李四'
        }];
        let target = ary.find((item, index) => item.id == 2);//找数组里面符合条件 的值,当数组中元素id等于2的查找出来,注意,只会匹配第一个
        

        findIndex()

        用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1

        let ary = [1, 5, 10, 15];
        let index = ary.findIndex((value, index) => value > 9);
        console.log(index); // 2
        

        includes()

        判断某个数组是否包含给定的值,返回布尔值。

        [1, 2, 3].includes(2) // true
        [1, 2, 3].includes(4) // false
        

        String 的扩展方法

        模板字符串 //用反引号

        let name = '张三';  let sayHello = `hello,my name is ${name}`; // hello, my name is zhangsan模板字符串中可以解析变量、换行、调用函数
        

        startsWith() 和 endsWith()

        表示参数字符串是否在原字符串的头部/尾部,返回布尔值

        repeat()

        repeat方法表示将原字符串重复n次,返回一个新字符串

        Set 数据结构

        类似于数组,但是成员的值都是唯一的,没有重复的值。

        const  常量名 = new Set();
        

        包含的方法:

        1.add(value):添加某个值,返回 Set 结构本身

        2.delete(value):删除某个值,返回一个布尔值,表示删除是否成功

        3.has(value):返回一个布尔值,表示该值是否为 Set 的成员

        4.clear():清除所有成员,没有返回值

        八.node

        Node环境 中的 Javascript

        node.js:Javascript的服务器端运行环境,可以让程序员使用Javacript来实现服务器端的编程,没有浏览器和HTML的概念,没有 BOM 和 DOM

        Node中的js组成:ECMAScript核心 + 全局成员 +核心API模块

        ​ 全局成员:console、setInterval、setTimeout…

        ​ 核心API模块:Node平台提供的一些API,是Node独有的

        node下载网站http://nodejs.cn/

        REPL环境

        打开任意终端,输入node并回车,就能进入

        按两次ctrl + c 退出REPL环境

        npm

        全局包

        1. **如何安装全局包:**运行 npm install 包名 -g 即可;其中 -g 参数,表示 把包安装到全局目录中的意思;
        2. 全局包的安装目录:`C:\Users\用户目录\AppData\Roaming\npm
        3. **如何卸载全局包:**要卸载某个全局的包,直接运行npm uninstall 包名 -g即可;其中 uninstall 表示卸载的意思;

        本地包

        1. **注意:**如果拿到一个空项目,必须在当前项目根目录中,先运行 npm init或者npm init -y 命令,初始化一个package.json的配置文件,否则包无法安装到本地项目中;
        2. **如何安装本地包:**运行npm i 包名 --save 即可安装本地包;都安装到了当前项目的 node_modules目录下;
          • 如果大家用的是npm 5.x的版本,可以不指定--save命令,如果用的是 npm 3.x 的版本,则需要手动指定 --save
        3. package-lock.json文件中记录了曾经装过的包的下载地址,方便下次直接下载包,能够加快装包的速度,提升装包的体验;
        4. **如何卸载本地包:**使用 npm uninstall/remove 包名 -S/-D即可卸载指定的本地包;

        其它常用命令

        1. --save 的缩写是 -S
        2. --save-dev的缩写是 -D
        3. install 的缩写是 i
        4. 注意:dependencies 节点,表示项目上线部署时候需要的依赖项;devDependencies节点,表示项目在开发阶段需要的依赖项,但是当项目要部署上线了,devDependencies节点中的包,就不再需要了!
        5. 注意:当使用 npm i快速装包的时候,npm会检查package.json文件中,所有的依赖项,然后都为我们安装到项目中
        6. --production 表示只安装 dependencies 节点下,记录的包,不安装devDependencies节点下的包;当项目要上线了,才会使用--production命令

        解决 npm 下载慢问题

        1. 如何安装cnpm:运行 npm i cnpm -g 即可;
        2. 如何使用cnpm:在装包的时候,只需要把 npm 替换成 cnpm 即可,例如:
          • 使用 npm 安装 jquery:运行 npm i jquery -S
          • 使用 cnpm 安装 jquery: 运行 cnpm i jquery -S

        安装node_modules里的插件

        npm install --save

        1.fs文件、path路径、第三方模块、模块查找规则

        fs文件系统

        const fs = require(‘fs’); //导入fs文件操作模块

        文件读取

        fs.readFile( __dirname + '/文件路径'[, '编码格式默认为null'] , function(err对象,data读取成功的结果 ){ 
          if(err) return console.log(err.message);	//如果err为null 就证明读取成功了 如果为true 则失败
        console.log( data ); });
        
        

        文件写入

        fs.writeFile( __dirname + '/文件路径', 写入内容[, '编码格式默认为utf-8'] , function(err){
           if(err) return console.log(err.message); //如果文件写入失败则报错
          console.log( '文件写入成功' );
        } )  //要写入的文件不存在则直接写入,如果已经存在则会覆盖之前的文件
        

        文件内容追加

        fs.appendFile(__dirname + '/文件路径', 追加内容[, '编码格式默认为utf-8'] , function(err){
        if(err) return console.log(err.message); //如果文件内容追加失败则报错
          console.log( '文件内容追加成功' );
        })
        

        如果要追加的文件路径不存在,则会先创建这个文件,再向创建的文件中追加内容

        fs模块操作文件时路径问题

        解决方案:使用node中提供的 __dirname 表示当前这个文件所处的磁盘目录

        还有一种 __filename 表示当前这个文件的完整路径,包含了具体的文件名

        读取文件信息

        fs.stat(__dirname + '/文件路径', function(err, stats){
        if(err) return console.log(err.message); //如果文件内容追加失败则报错
          console.log( '文件内容读取成功' );
          console.log( stats.size );	//文件大小
          console.log( stats.birthtime );	//创建时间
          console.log( stats.isFile );	//判断是否为文件
          console.log( stats.isDirectory);	//判断是否为目录
        })
        

        复制文件

        fs.copyFile( '被拷贝的源文件路径,包含文件名称', '拷贝出的目标文件路径,包含名称'[,拷贝操作修饰符默认0],function(err){
        if(err) return console.log(err.message); //如果拷贝失败则报错
           console.log( '拷贝成功' );
        } )	//如果要拷贝出的目标文件已经存在则会覆盖,如果不存在则会新建
        

        路径操作

        path.join([…paths])

        const path = require('path')
        path.join(__dirname, '相对路径')
        

        其他:

        const path = require('path')
        
        // console.log(path.sep) // 路径分隔符
        
        const str = 'c:/a/b/c/1.txt'
        
        console.log(path.basename(str)) // 获取文件名称的
        console.log(path.dirname(str)) // 获取文件所在的路径的
        console.log(path.extname(str)) // 获取文件的扩展名
        

        Javascript 的单线程和异步

        Javascript 的解析和执行一直是单线程的,但是**宿主环境(浏览器或node)**是多线程的;

        异步任务是由宿主环境开启子线程完成,并通过事件驱动、回调函数、队列,把完成的任务, 交给主线程执行;

        Javascript解析引擎,一直在做一个工作,就是从任务队列里提取任务,放到主线程里执行

        CommonJS 规范

        1. 作用:是一套 Javascript 的模块化规范,规定了 模块的特性各模块之间如何相互依赖
        2. 用途:Node.js 中使用了 CommonJS 规范;
        3. 特点:同步加载模块;不适合在浏览器端使用;
        4. CommonJS规范都定义了哪些内容:wiki 对于 Modules 的描述

        模块作用域 和 全局作用域

        在Node.js中有两个作用域,分别是 全局作用域 和 模块作用域;

        1. 全局作用域使用 global 来访问,类似于浏览器中的window

        2. 每个 Javascript 文件,都是一个单独模块,每个模块都有自己独立的作用域,因此:模块中的成员,默认无法被其它模块访问。

        3. 如果在某个模块内部,想为 全局的 global 作用域挂载一些属性,需要显示的调用global.***来挂载;

        4. 注意:在开发中,一般情况下,不推荐使用global全局作用域来共享成员,会存在全局变量污染问题;

          var b = 20
          
          // console.log(global.b)
          global.b = b
          
          global.say = function () {
            console.log('这是挂载到全局的 say 方法')
          }
          
          console.log(global.b)
          global.say()
          

        模块作用域

        1. module(模块标识)

          module 属性是 Common JS 规范中定义的,它是一个对象,表示当前这个具体的 js 模块;

        2. require(引用模块)

          每一个实现了 CommonJS 规范的模块,必须定义一个 require() 函数,使用这个 require 函数,就能够 很方便的导入其它 模块中的成员,供自己使用;

        3. exports(暴露模块成员)

          每一个模块中,如果想要把自己的一些私有成员,暴露给别人使用,那么,必须实现一个 exports 对象,通过exports对象,可以方便的把模块内私有的成员,暴露给外界使用;

        module.exports 和 exports 的关系

        1. module.exportsexports 默认引用了同一个空对象;
        2. module.exportsexports 作用一致,都可以向外暴露成员;
        3. 一个模块作用域中,向外暴露私有成员时,永远以 module.exports 为准;
        module.exports = {}
        

        模块成员的分类

        模块成员,根据一些区别,又可以分为三大类: 核心模块、第三方模块、用户自定义模块

        1.核心模块

        1. 什么是核心模块:
          • 随着Node.js的安装包,一同安装到本地的模块,叫做核心模块;
          • 例如:fspath等模块,都是由Node.js官方提供的核心模块;
          • 只要大家在计算机中,安装了Node这个应用程序,那么,我们的计算机中就已经安装了所有的 核心模块;
        2. 如何使用核心模块require('核心模块标识符')

        2.第三方模块

        1. 什么是第三方模块:

          • 一些非官方提供的模块,叫做第三方模块;
          • 注意,第三方模块,并不在我们的计算机上;
          • 如果大家需要使用某些第三方模块,必须去一个叫做 NPM 的网站上搜索并下载才能使用;
        2. 如何使用第三方模块:

          • 先从 npm 官网上下载指定的第三方模块

          • 使用 require('第三方模块的名称标识符')来导入这个模块

          • 根据 第三方模块的 官方文档,尝试使用

          • npm install package => 用npm命令安装(下载)第三方模块 (文件模块)

          • gulp

            gulp的安装:

            1. 定位终端到项目目录 执行 npm install gulp -s 本地安装gulp的库文件
            2. 执行 npm install gulp-cli -g 全局安装gulp的命令行工具

            gulp的插件:

            1. gulp-htmlmin:html代码压缩 安装 npm install --save gulp-htmlmin
            2. gulp-file-include:html公共模块提取 npm install gulp-file-include
            3. gulp-less:less语法转化 npm install gulp-less
            4. gulp-csso:css压缩 npm install gulp-cssgo
            5. gulp-babel:JavaScript语法转化 npm install --save-dev gulp-babel @babel/core @babel/preset-env
            6. gulp-uglify:压缩混淆js代码 npm install --save-dev gulp-uglify
            7. !!!!!!注意!Gulp 4最大的变化就是你不能像以前那样传递一个依赖任务列表 如果Gulp是4.0的版本需要手动指定版本号 比如 npm install gulp@3.9.1 -D

            gulp语法:

            ​ 1.gulp.task() 建立gulp任务

            ​ 2.gulp.src() 获取任务要处理的文件

            ​ 3.gulp.dest() 输出文件

            ​ 4.gulp.watch() 监控文件的变化

        3. 如何卸载

          npm unintall package => 用npm命令卸载包

        3.用户自定义模块

        1. 什么是用户模块:
          • 程序员在自己项目中写的 Javascript 文件,就叫做 用户自定义模块;
        2. 如何使用用户模块:require('路径标识符')

        模块查找规则

        • 当require方法接收不带路径的模块名字
          • Node.js会假设它是系统模块
          • Node.js会去node_modules文件夹中
            • 首先看是否有该名字的JS文件
            • 再看是否有该名字的文件夹
            • 如果是文件夹看里面是否有index.js
            • 如果没有index.js查看该文件夹中的package.json中的main选项确定模块入口文件
            • 否则找不到报错
        • 当require方法接收带路径的模块名字
          • require方法接收相对路径,相对于当前文件
          • 先找同名JS文件再找同名JS文件夹
          • 找文件夹中index.js否则去package.js中查找main选项确定入口文件
          • 否则找不到报错

        package.json

        项目描述文件,记录当前项目信息,例如项目名称、版本、作者、github地址、当前项目依赖了哪些第三方模块,目的是方便他人了解项目信息,下载项目依赖文件。

        该文件一般被放置在项目的根目录下,使用npm init命令生成。

        项目依赖

        在项目的开发阶段和线上运营阶段,都需要依赖的第三方包,称为项目依赖。

        使用npm install 包名命令下载的文件会默认被添加到package.json文件的dependencies字段中。

        开发依赖

        在项目的开发阶段需要依赖,线上运营阶段不需要依赖的第三方包,称为开发依赖。

        使用npm install 包名 --save-dev命令将包添加到package.json文件的devDependencies字段中。

        只安装项目运行依赖(dependencies)

        npm install --production
        

        为什么记录依赖项

        1. Node.js中下载的第三方包文件拥有非常多的细碎文件,将项目通过移动硬盘传递给别人时传输速度非常慢.
        2. 使用git工具管理项目时,不希望git管理node_modules文件夹,也不会将其上传到github中.

        当其他人获取到项目时,可以在项目根目录下执行npm install 命令,npm工具会自动去package.json文件中查找项目依赖文件并下载.

        1. 当项目上线以后,可以直接运行npm install --production下载项目依赖,避免下载项目开发依赖。

        2.服务器、http、静态资源、promise、异步函数

        创建web服务器

        // 引用系统模块
        const http = require('http');
        // 创建web服务器
        const server = http.createServer();
        // 当客户端发送请求的时候
        server.on('request', (req, res) => {
        	// 设置响应头
        	res.writeHead(200, {
        		'Content-Type': 'text/html;charset=utf8'
        	});
        	// 设置响应体
        	res.write('<h1>哈哈哈</h1>');
        	// 结束请求
        	res.end();
        });
        // 监听3000端口
        server.listen(3000, error => {
            if (!error) {
            	console.log('服务器已启动,监听3000端口,请访问 localhost:3000')    
            }
        });
        

        http协议

        req.url //获取请求地址

        req.headers //获取请求报文

        req.method //获取请求方法

        http状态码

        • 200请求成功
        • 404请求的资源没有找到
        • 500服务器端有错误
        • 400客户端请求有语法错误

        内容类型

        • text/plain
        • text/html
        • text/css
        • application/javascript
        • image/jpeg
        • application/json

        GET传参

        参数被放置在地址栏中,格式为:name=zhangsan&age=20

        // 处理get参数
        const url = require('url');
        let { query } = url.parse(req.url, true);
        

        POST传参

        参数被放置在请求体中,格式和GET参数相同。

        // 处理post参数
        // 由于post传递的参数数据量比较大,在网络中并不是一次性传递完成的,而是分成了多次传递
        // 所以在接收的时候也需要分为多次接收
        // 在NodeJs中接收post参数需要使用事件完成
        const querystring = require('querystring');
        router.post('/add', (req, res) => {
            //接收post请求参数
            let formData = '';
            req.on('data', chunk => formData += chunk);//开始接受
            req.on('end', async() => {//接受完
              //querystring.parse(formData) 把字符串转换为对象
                await Student.create(querystring.parse(formData))
                res.writeHead(301, {
                    Location: '/list'
                })
                res.end()
            })
        })
        

        路由

        路由是指URL地址与程序的映射关系,更改URL地址可以改变程序的执行结果。简单说就是请求什么响应什么。

        // 1.引入系统模块http
        // 2.创建网站服务器
        // 3.为网站服务器对象添加请求事件
        // 4.实现路由功能
        // 	1.获取客户端的请求方式
        // 	2.获取客户端的请求地址
        const http = require('http')
        const url = require('url')
        const app = http.createServer()
        app.on('request', (req, res) => {
            const method = req.method.toLowerCase()
            const pathname = url.parse(req.url).pathname
          //let { pathname, query } = url.parse(req.url, true) //返回值为对象
                // 防止中文乱码
            res.writeHeader(200, {
                'Content-Type': 'text/html; charset=utf-8'
            })
            if (method === 'get') {
                if (pathname === '/' || pathname === '/index') {
                    res.end('首页')
                } else if (pathname === '/list') {
                    res.end('列表页')
                } else {
                    res.end('无结果')
                }
            }
            if (method === 'post') {
        
            }
        })
        app.listen(3000)
        console.log('to http://127.0.0.1:3000')
        

        客户端请求方式

        1. 浏览器地址栏
        2. Form表单提交
        3. link标签的href属性
        4. script标签的src属性
        5. image标签的src属性

        静态资源获取

        服务器端不需要处理,可以直接响应给客户端的资源就是静态资源,例如CSS、JavaScript、image文件

        const http = require('http');
        const url = require('url');
        const path = require('path');
        const fs = require('fs');
        const mime = require('mime');
        
        const app = http.createServer();
        app.on('request', function(req, res) {
            //获取用户请求路径
            let pathname = url.parse(req.url).pathname
            pathname = pathname == '/' ? '/default.html' : pathname
            let paths = path.join(__dirname, 'public' + pathname)
            let type = mime.getType(paths)
            fs.readFile(paths, (err, date) => {
                if (err !== null) {
                    // 防止中文乱码
                    res.writeHeader(404, { //text/html能识别html标签;text/plain表示普通的文本字符串
                        'Content-Type': 'text/html; charset=utf-8'
                    })
                    res.writeHeader(200, {
                        'content-Type': type
                    })
                    return res.end('报错')
                }
                res.end(date)
            })
        })
        app.listen(3000, '127.0.0.1', function() {
            console.log('server running at http://127.0.0.1:3000');
        })
        

        promise

        Promise出现的目的是解决Node.js异步编程中回调地狱的问题

        //下面是用promise 读取静态资源文件
        const promisify = require('util').promisify;
        const fs = require('fs');
        /* let promise = new Promise((dome1, dome2) => {
            fs.readFile('./views/1.text', 'utf-8', (err, date) => {
                if (err !== null) {
                    dome2(err)
                } else {
                    dome1(date)
                }
            })
        })
        promise.then((date) => {
                console.log(date);
            })
            .catch((err) => {
                console.log(err);
        
            }) */
        function p1() {
            return new Promise((dome1, dome2) => {
                fs.readFile('./views/1.text', 'utf-8', (err, date) => {
                    if (err !== null) {
                        dome2(err)
                    } else {
                        dome1(date)
                    }
                })
            })
        }
        function p2() {
            return new Promise((dome1, dome2) => {
                fs.readFile('./views/2.text', 'utf-8', (err, date) => {
                    if (err !== null) {
                        dome2(err)
                    } else {
                        dome1(date)
                    }
                })
            })
        }
        p1().then((date) => {
                console.log(date);
                return p2()
            })
            .then((date) => {
                console.log(date);
            })
        

        异步函数

        异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了

        const fn = async () => {};
        async function fn () {}
        

        async关键字

        1. 普通函数定义前加async关键字 普通函数变成异步函数
        2. 异步函数默认返回promise对象
        3. 在异步函数内部使用return关键字进行结果返回 结果会被包裹的promise对象中 return关键字代替了resolve方法
        4. 在异步函数内部使用throw关键字抛出程序异常
        5. 调用异步函数再链式调用then方法获取异步函数执行结果
        6. 调用异步函数再链式调用catch方法获取异步函数执行的错误信息

        await关键字

        1. await关键字只能出现在异步函数中
        2. await promise await后面只能写promise对象 写其他类型的API是不不可以的
        3. await关键字可是暂停异步函数向下执行直到promise返回结果

        promisify改造函数

        //下面是异步函数读取文件代码示例:
        const fs = require('fs');
        // 改造现有异步函数api 让其返回promise对象 从而支持异步函数语法
        const promisify = require('util').promisify;
        // 调用promisify方法改造现有异步API 让其返回promise对象
        const readFile = promisify(fs.readFile);
        
        async function run() {
            let n1 = await readFile('./views/1.text', 'utf-8')
            let n2 = await readFile('./views/2.text', 'utf-8')
            console.log(n1);
            console.log(n2);
        
        }
        run()
        

        异步函数示例代码如下:

        // 1.在普通函数定义的前面加上async关键字 普通函数就变成了异步函数
        // 2.异步函数默认的返回值是promise对象
        // 3.在异步函数内部使用throw关键字进行错误的抛出
        // await关键字
        // 1.它只能出现在异步函数中
        // 2.await promise 它可以暂停异步函数的执行 等待promise对象返回结果后再向下执行函数
        
        // async function fn() {
        //     throw '发生了错误'
        //     return 123
        // }
        // fn().then((date) => {
        //         console.log(date);
        //     })
        //     .catch((err) => {
        //         console.log(err);
        //     })
        async function p1() {
            return 'p1'
        }
        async function p2() {
            return 'p2'
        }
        async function p3() {
            return 'p3'
        }
        async function run() {
            console.log(await p1());
            console.log(await p2());
            console.log(await p3());
        }
        run()
        

        3.数据库mongodb

        MongoDB数据库安装

        Node.js通常使用MongoDB作为其数据库,具有高性能,易使用,存储数据方便等特点,完全使用JavaScript语法即可操作。下载

        MongoDB可视化软件

        MongoDB可视化操作软件,使用图形界面操作数据库的一种方式。下载

        Mongoose第三方包

        使用Node.js操作MongoDB数据库需要依赖Node.js第三方包mongoose,使用npm install mongoose命令下载

        数据库连接

        const mongoose = require('mongoose');
        // 数据库连接 27017是mongodb数据库的默认端口
        // mongoose.connect('mongodb://账号名:密码@localhost:27017/数据库名字', { useNewUrlParser: true })
        mongoose.connect('mongodb://likai:550@localhost:27017/blog', { useNewUrlParser: true })
            .then(() => console.log('数据库连接成功'))
            .catch(() => console.log('数据库连接失败'));
        

        创建集合

        //连接数据库
        const mongoose = require('mongoose')
        mongoose.connect('mongodb://localhost/playground', { useNewUrlParser: true })
            .then(() => {
                console.log('数据库连接成功');
            })
            .catch((err) => {
                console.log(err, '数据库连接失败');
            })
        //创建集合规则(类似于设计数据库表结构)
        const courseSchema = new mongoose.Schema({
                name: String,
                author: String,
                ispub: Boolean
            })
        //使用规则创建集合,第一个参数是集合名称(第一个字母要大写) 第二个参数是集合规则
        const Course = mongoose.model('Course', courseSchema)
        

        添加数据

        //第一种插入数据方式
        // const dome1 = new Course({
        //     name: 'kk',
        //     author: 'student',
        //     ispub: true
        // })
        // dome1.save()
        
        //第二种插入数据方式
        Course.create({
                name: 'qiuqiu',
                author: 'student',
                ispub: true
            })
            .then(doc => {
                console.log(doc);
            })
            .catch(err => {
                console.log(err);
            })
        

        查找

        //1.全部查询
        // User.find().then(date => {
        //     console.log(date);
        // })
        User.find({
            _id: '5c09f267aeb04b22f8460968'
        }).then(date => {
            console.log(date); //输出值是个数据
        })
        User.findOne({
                // _id: '5c09f236aeb04b22f8460967'
            }).then(date => {
                console.log(date); //输出值是个集合,并且是集合中的第一条
            })
        //2.范围查询
        User.find({
                age: { $gt: 20, $lt: 50 }
            }).then(date => {
                console.log(date);
        
            })
        //3.包含查询
        User.find({
                hobbies: { $in: ['足球'] }
            }).then(date => {
                console.log(date);
                console.log('-----------');
            })
        //4.字段查询,多个字段中间以空格隔开,前面加 - 表示不查询该字段
        User.find().select('name age -_id').then(date => {
                console.log(date); //返回值为数组包含数条集合
                console.log('-----------');
            })
        //5.将查找的数据进行升序排序,若降序排列,在字段名前面加 - ,下面以年龄为示例
        User.find().sort('age').then(date => {
                console.log(date); //返回值为数组包含数条集合
            })
        //6.skip()跳过多少条数据,  llimit()限制查询结果的数量
        User.find().skip(2).limit(2).then(date => {
            console.log(date); //返回值为数组包含数条集合
        })
        

        删除

        // 查找到一条文档并且删除
        // 返回删除的文档
        // 如何查询条件匹配了多个文档 那么将会删除第一个匹配的文档
        User.findOneAndDelete({ _id: '5c09f267aeb04b22f8460968' })
            .then(date => {
                console.log(date);
            })
            // 删除多条文档
            //返回值为{ n:4, ok:1 }  n为删除的数量,ok为1表示删除成功
            // User.deleteMany({ _id: '5c09f267aeb04b22f8460968' })
            //     .then(date => {
            //         console.log(date);
            //     })
        

        修改

        //修改单个,返回值{ n: 1, nModified: 1, ok: 1 } n代表受影响的数据个数, nModifie表示修改的数据个数, ok为1表示成功
        User.updateOne({ name: '赵六' }, { name: '赵云' })
            .then(date => {
                console.log(date);
            })
            //修改多个
        User.updateMany({}, { age: 88 })
            .then(date => {
                console.log(date);
            })
        

        验证规则

        // 创建集合规则,并添加规则验证
        const pot = new mongoose.Schema({
            title: {
                type: String,
                required: [true, '请传入文章标题'], //必选字段,第二参数为报错时提示信息
                maxlength: 10, //传入字符串最大长度
                minlength: 2, //传入字符串最小长度
                trim: true //去除字符串两端的空格
        
            },
            age: {
                type: Number,
                min: 2, //数值最小值
                max: 100 //数值最大值
            },
            publishDate: {
                type: Date,
                default: Date.now // 默认值
            },
            category: {
                type: String,
                // 枚举 列举出当前字段可以拥有的值
                enum: {
                    values: ['html', 'css', 'javascript', 'node.js'],
                    message: '分类名称要在一定的范围内才可以'
                }
            },
            author: {
                type: String,
                validate: {
                    validator: v => {
                        // 返回布尔值
                        // true 验证成功,false 验证失败
                        // v 要验证的值
                        return v && v.length > 4
                    },
                    message: '传入的值不符合验证规则' // 自定义错误信息
                }
            }
        });
        

        多集合联合查询(集合关联)

        通常不同集合的数据之间是有关系的,例如文章信息和用户信息存储在不同集合中,但文章是某个用户发表的,要查询文章的所有信息包括发表用户,就需要用到集合关联。

        // 用户集合
        const User = mongoose.model('User', new mongoose.Schema({ name: { type: String } })); 
        // 文章集合
        const Post = mongoose.model('Post', new mongoose.Schema({
            title: { type: String },
            // 使用ID将文章集合和作者集合进行关联
            author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
        }));
        //联合查询
        Post.find()
              .populate('author')
              .then((err, result) => console.log(result));
        

        在catch中获取错误信息

        Post.create({title:'aa', age: 60, category: 'java', author: 'bd'})
        	.then(result => console.log(result))
        	.catch(error => {
        		// 获取错误信息对象
        		const err = error.errors;
        		// 循环错误信息对象
        		for (var attr in err) {
        			// 将错误信息打印到控制台中
        			console.log(err[attr]['message']);
        		}
        	})
        

        数据库导入文档数据

        mongoimport -d 数据库名称 -c 集合名称 --file '要导入的数据文件名(包含路径)'
        

        mongoDB数据库添加账号

        1. 以系统管理员的方式运行powershell
        2. 连接数据库 mongo
        3. 查看数据库 show dbs
        4. 切换到admin数据库 use admin
        5. 创建超级管理员账户 db.createUser()
        6. 切换到blog数据 use blog
        7. 创建普通账号 db.createUser()
        8. 卸载mongodb服务

        ​ 停止服务 net stop mongodb

        ​ mongod --remove

        ​ 9.创建mongodb服务

        ​ mongod --logpath=“C:\Program
        Files\MongoDB\Server\4.1\log\mongod.log” --dbpath=“C:\Program
        Files\MongoDB\Server\4.1\data” --install –-auth

        ​ 10.启动mongodb服务 net start mongodb

        ​ 11.在项目中使用账号连接数据库

        ​ mongoose.connect(‘mongodb://likai:550@localhost:27017/blog’, { useNewUrlParser: true })

        ​ mongoose.connect(‘mongodb://账号名:密码@localhost:27017/数据库名字’, { useNewUrlParser: true })

        创建项目数据库账号

        1.mongo

        2.use admin

        3.db.auth(‘root’,‘root’)

        4.use 项目使用的数据库名

        5.db.createUser({user:‘likai’,pwd:‘550’,roles:[‘readWrite’]})

        6.exit

        4.模板引擎、Express

        art-template下载

        高性能 JavaScript 模板引擎,使用npm install art-template命令下载。

        通过调用模板引擎提供的template函数,告知模板引擎将特定模板和特定数据进行拼接,最终返回拼接结果

        //导入模板引擎
        const template = require('art-template');
        const path = require('path')
            // 设置模板的根目录
        template.defaults.root = path.join(__dirname, 'views');
        // 配置模板的默认后缀
        template.defaults.extname = '.html';
            // template方法是用来拼接字符串的
            // 参数1. 模板路径 绝对路径
            // 参数2. 要在模板中显示的数据 对象类型
            // 返回拼接好的字符串
        const html = template('index.art'), {
            name: '张三',
            age: 20
        })
        console.log(html);
        

        模板语法

        标准语法: {{ 数据 }}
        原始语法:<%= 数据  %>
        

        原文输出

        如果数据中携带HTML标签,默认不会解析标签,会将其转义后输出。使用以下方式可以解析标签。

        标准语法: {{ @数据 }}
        原始语法:<%- 数据  %>
        

        条件判断

        <!-- 标准语法 --> 
         {{if 条件}} ... {{/if}}
         {{if v1}} ... {{else if v2}} ... {{/if}}
         <!-- 原始语法 -->
         <% if (value) { %> ... <% } %>
         <% if (v1) { %> ... <% } else if (v2) { %> ... <% } %>
        

        数据循环

        <!-- 标准语法 --> 
        {{each 数据}}
             {{$index}} {{$value}}
         {{/each}}
          <!-- 原始语法 -->
         <% for(var i = 0; i < target.length; i++){ %>
             <%= i %> <%= target[i] %> //带等号表示输出
         <% } %>
        

        子模板

        使用子模板可以将网站公共区块(头部、底部)抽离到单独的文件中。

          <!-- 标准语法 -->
         {{include '模板路径'}}
          <!-- 原始语法 -->
         <% include('模板路径') %>
        

        模板继承

        使用模板继承可以将网站HTML骨架抽离到单独的文件中,其他页面模板可以继承骨架文件。

        {{extend './layout.html'}}//要继承的html文件
        {{block 'head'}} ... {{/block}} //内容填充
        

        模板配置

        下载: npm install dateformat
        

        代码示例:

        const dateformat = require('dateformat');
        // 导入模板变量 用于处理日期格式的方法
        template.defaults.imports.dateformat = dateformat;
        //日期格式 {{dateformat($value.name名,'yyyy-mm-dd')}}
        

        第三方模块 router

        功能:实现路由

        使用步骤:

        1. 获取路由对象

        2. 调用路由对象提供的方法创建路由

        3. 启用路由,使路由生效

          const getRouter = require('router')
          const router = getRouter();//创建路由
          
          router.get('/list', async(req, res) => {
              let student = await Student.find() //查询学生信息
              let html = template('list.art', {
                  students: student
              })
              res.end(html)//最后要有一个返回值
          })
          
          app.on('request', (req, res) => {
              router(req, res, () => {} )
          })
          

        实现静态资源访问

        • 第三方模块serve-static

          1. 引入serve-static模块获取创建静态资源(比如css,js等)服务功能的方法

          2. 调用方法创建静态资源服务并指定静态资源服务目录

          3. 启用静态资源服务功能

            const serveStatic = require('serve-static')
            const serve = serveStatic('静态资源目录')
            app.on('request', () => { 
                serve(req, res)
            })
            app.listen(3000)
            

        Express

        Express是一个基于Node平台的web应用开发框架,提供一系列强大特性,帮助你创建各种 Web应用。

        使用npm install express 进行本地安装。

        中间件

        使用app.use()方法定义中间件。

        • 该方法可以传递一个函数作为参数,表示任何任何请求都会经过该中间件,都会执行该参数内部的代码。

          app.use((req, res, next) => {
              console.log(req.url);
              next();
          });
          
          • 中间件函数有三个参数,分别为请求对象req、响应对象res、释放控制权方法next。
          • 中间件函数中的代码执行完成之后需要调用next()方法,才能开始执行下一个中间件,否则请求将挂起。
        • 该方法的第一个参数也可以是请求路径,表示只有该请求路径才会经过该中间件。

          app.use('/user', (req, res, next) => {
             console.log(req.method);
             next();
          });
          

        中间件错误处理

        app.get('/index', (req, res, next) => {
        	// throw new Error('程序发生了未知错误')
        	fs.readFile('./01.js', 'utf8', (err, result) => {
        		if (err != null) {
        			next(err)
        		}else {
        			res.send(result)
        		}
        	})
          })
        // 下面是错误处理
        app.use((err, req, res, next) => {
        	res.status(500).send(err.message);
        })
        

        异步函数错误捕捉

        const express = require('express');
        const fs = require('fs');
        const promisify = require('util').promisify;
        const readFile = promisify(fs.readFile);
        
        app.get('/index', async (req, res, next) => {
        	try {
        		await readFile('./aaa.js')
        	}catch (ex) {
        		next(ex);
        	}
        })
        

        构建模块化路由

        第一种:在同一个页面

         const express = require('express') 
         // 创建路由对象
         const home = express.Router();
         // 将路由和请求路径进行匹配
         app.use('/home', home);
          // 在home路由下继续创建路由
         home.get('/index', () => {
                  //  /home/index
                 res.send('欢迎来到博客展示页面');
         });
        

        第二种:在多个页面

         // home.js
         const express = require('express') 
         // 创建路由对象
         const home = express.Router(); 
         home.get('/index', () => {
             res.send('欢迎来到博客展示页面');
         });
         module.exports = home;
        
         // admin.js
         const express = require('express') 
         // 创建路由对象
         const admin = express.Router();
         admin.get('/index', () => {
             res.send('欢迎来到博客管理页面');
         });
         module.exports = admin;
        
         // app.js
        const express = require('express');
        // 创建网站服务器
        const app = express();
         const home = require('./route/home.js');
         const admin = require('./route/admin.js');
         app.use('/home', home);
         app.use('/admin', admin);
        // 端口监听
        app.listen(3000);
        console.log('to http://127.0.0.1:3000')
        

        获取get请求参数

        // 引入express框架
        const express = require('express');
        // 创建网站服务器
        const app = express();
        
        app.get('/index', (req, res) => {
            // 获取get请求参数
            res.send(req.query)
        })
        // 端口监听
        app.listen(3000);
        console.log('to http://127.0.0.1:3000')
        

        获取post请求参数

        Express中接收post请求参数需要借助第三方包 body-parser

        // 引入express框架
        const express = require('express');
        const bodyParser = require('body-parser');
        // 创建网站服务器
        const app = express();
        // 拦截所有请求
        // extended: false 方法内部使用querystring模块处理请求参数的格式
        // extended: true 方法内部使用第三方模块qs处理请求参数的格式
        app.use(bodyParser.urlencoded({extended: false}))
        
        app.post('/add', (req, res) => {
        	// 接收post请求参数
        	res.send(req.body)
        })
        // 端口监听
        app.listen(3000);
        console.log('to http://127.0.0.1:3000')
        

        app.use方法

        // 引入express框架
        const express = require('express');
        const bodyParser = require('body-parser');
        // 创建网站服务器
        const app = express();
        
        app.use(fn({ a: 2 }))
        
        function fn(obj) {
            return function(req, res, next) {
                if (obj.a == 1) {
                    console.log(req.url)
                } else {
                    console.log(req.method)
                }
                next()
            }
        }
        
        app.get('/', (req, res) => {
                // 接收post请求参数
                res.send('ok')
            })
            // 端口监听
        app.listen(3000);
        console.log('to http://127.0.0.1:3000')
        

        路由参数

        // 引入express框架
        const express = require('express');
        const bodyParser = require('body-parser');
        // 创建网站服务器
        const app = express();
        
        app.get('/index/:id/:name/:age', (req, res) => {
          // 客户端请求时地址栏应该写成这样
        // http://localhost:3000/list/12/zhangsan /20
          
            // 接收post请求参数
            res.send(req.params)
        })
        // 端口监听
        app.listen(3000);
        console.log('to http://127.0.0.1:3000')
        

        express静态资源

        通过 Express 内置的 express.static 可以方便地托管静态文件,例如图片、CSS、JavaScript 文件等。

        app.use(express.static('public'));
        

        现在,public 目录下面的文件就可以访问了。

        http://localhost:3000/images/kitten.jpg
        http://localhost:3000/css/style.css
        http://localhost:3000/js/app.js
        http://localhost:3000/images/bg.png
        http://localhost:3000/hello.html
        

        express模板引擎

        使用npm install art-template express-art-template命令进行安装。

        const express = require('express');
        const path = require('path');
        const app = express();
        // 1.当渲染后缀为art的模板时 所使用的模板引擎是什么
        //  参数1模板后缀,参数2使用的模板引擎
        app.engine('art', require('express-art-template'))
            // 2.告诉express框架模板存放的位置是什么
        app.set('views', path.join(__dirname, 'views'))
            // 3.告诉express框架模板的默认后缀是什么
        app.set('view engine', 'art');
        
        app.get('/index', (req, res) => {
            // 1. 拼接模板路径
            // 2. 拼接模板后缀
            // 3. 哪一个模板和哪一个数据进行拼接
            // 4. 将拼接结果响应给了客户端
            // 第一个参数模板的路径(包含名字),第二个参数是一个对象
            res.render('index', {
                msg: 'message'
            })
        });
            // 端口监听
        app.listen(3000);
        console.log('to http://127.0.0.1:3000')
        

        app.locals

        const express = require('express');
        const path = require('path');
        const app = express();
        // 模板配置
        app.engine('art', require('express-art-template'))
        app.set('views', path.join(__dirname, 'views'))
        app.set('view engine', 'art');
        //将变量设置到app.locals对象中,这个数据在所有的模板中到可以获得到
        app.locals.users = [{
            name: 'zhangsan',
            age: 20
        }, {
            name: '李四',
            age: 30
        }]
        
        app.get('/index', (req, res) => {
            res.render('index', {
                msg: '首页'
            })
        });
         // 端口监听
        app.listen(3000);
        console.log('to http://127.0.0.1:3000')
        

        5.博客blog知识点

        密码加密bcrypt

        哈希斯加密是单程加密方式

        在加密的密码中加入随机字符串可以增加密码被破解的难度

        //导入bcrypt模板
        const bcrypt = require('bcrypt')
        //生成随机字符串 gen => generate生成 salt盐
        let salt = await bcrypt.genSalt(10)
        //使用随机字符串对密码进行加密
        let pass = await bcrypt.hash('明文密码',salt)
        
        //密码比对,返回布尔值
        let isEqual = await bcrypt.compare('明文密码','加密密码')
        

        bcrypt依赖的其他环境

        1.python 2.x

        2.node-gyp 安装命令:npm install -g node-gyp

        3.windows-build-tools(window系统需要安装)

        安装命令:npm install --global --production windows-build-tools

        cookie与session

        cookie:浏览器在电脑硬盘中开辟的一块空间,在客户端,主要供服务器端存储数据。

        • cookie中的数据是以域名的形式进行区分的。
        • cookie中的数据是有过期时间的,超过时间数据会被浏览器自动删除。
        • cookie中的数据会随着请求被自动发送到服务器端。

        session:实际上就是一个对象,存储在服务器端的内存中,在session对象中也可以存储多条数据,每一条数据都有一个sessionid做为唯一标识。

        在node中使用express-session模块实现session功能

        const session = require('express-session');
        app.use(session({ secret: 'secret key' }));
        

        在app.js中引入模块

        // 导入express-session模块
        const session = require('express-session');
        // 配置session
        app.use(session({
        	secret: 'secret key',
        	saveUninitialized: false,
        	cookie: {
        		maxAge: 24 * 60 * 60 * 1000
        	}
        }));
        

        在用户页面从session中获取数据

        // 创建用户列表路由
        admin.get('/user',(req,res)=>{
          res.render('admin/user',{
            msg:req.session.username
          })
        })
        

        实现退出功能

        1.删除session

        2.删除cookie

        3.重定向到用户登录页面

        module.exports = (req, res) => {
        	// 删除session
        	req.session.destroy(function () {
        		// 删除cookie
        		res.clearCookie('connect.sid');
        		// 重定向到用户登录页面
        		res.redirect('/admin/login');
        	});
        }
        

        express的页面重定向

          res.redirect('/admin/user')
        

        joi

        JavaScript对象的规则描述语言和验证器

        安装 npm install joi

        const Joi = require('joi');
        const schema = {//alphanum()字母字符串
            username: Joi.string().alphanum().min(3).max(30).required().error(new Error(‘错误信息’)),
            password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
            access_token: [Joi.string(), Joi.number()],//表示两种类型都可以
            birthyear: Joi.number().integer().min(1900).max(2013),//integer()整数
            email: Joi.string().email()//邮箱格式
          //valid(0, 1)值必须为0或1
            static: Joi.number().valid(0, 1).error(new Error('状态值非法'))
        };
        async function run () {
        	try {
        		// 实施验证
        		await Joi.validate({ username: 'abc', birthyear: 1994 }, schema);
        	}catch (ex) {
        		console.log(ex.message);
        		return;
        	}
        	console.log('验证通过')
        

        formidable

        作用:解析表单,支持get请求参数,post请求参数、文件上传

        安装: npm install formidable

         // 引入formidable模块
         const formidable = require('formidable');
         // 创建表单解析对象
         const form = new formidable.IncomingForm();
         // 设置文件上传路径
         form.uploadDir = "/my/dir";
         // 是否保留表单上传文件的扩展名
         form.keepExtensions = true;
         // 对表单进行解析
         form.parse(req, (err, fields, files) => {
             // fields 存储普通请求参数(普通表单数据)
                 // files 存储上传的文件信息
         });
        

        FileReader

        //文件读取 
        var reader = new FileReader();
         reader.readAsDataURL('文件');
         reader.onload = function () {
             console.log(reader.result); 
         }
        

        数据分页 mongoose-sex-page

        const pagination = require('mongoose-sex-page');
        // page 指定当前页
            // size 指定每页显示的数据条数
            // display 指定客户端要显示的最多页码数
            // exec 向数据库中发送查询请求
            // 查询所有文章数据
        pagination(集合构造函数).page(1) .size(20) .display(8) .exec();
        

        config

        作用:允许开发人员将不同运行环境下的应用配置信息抽离到单独的文件中,模块内部自动判断当前应用的运行环境,

        并读取对应的配置信息,极大提供应用配置信息的维护成本,避免了当运行环境重复的多次切换时,手动到项目代码

        中修改配置信息

        使用步骤:

        1. 使用npm install config命令下载模块
        2. 在项目的根目录下新建config文件夹
        3. 在config文件夹下面新建default.json、development.json、production.json文件
        4. 在项目中通过require方法,将模块进行导入
        5. 使用模块内部提供的get方法获取配置信息
        {
        	"db": {
        		"user": "itcast",
        		"host": "localhost",
        		"port": "27017",
        		"name": "blog"
        	}
        }
        
        mongoose.connect(`mongodb://${config.get('db.user')}:${config.get('db.pwd')}@${config.get('db.host')}:${config.get('db.port')}/${config.get('db.name')}`, {useNewUrlParser: true })
        	.then(() => console.log('数据库连接成功'))
        	.catch(() => console.log('数据库连接失败'))
        

        将敏感配置信息存储在环境变量中

        1. 在config文件夹中建立custom-environment-variables.json文件
        2. 配置项属性的值填写系统环境变量的名字
        3. 项目运行时config模块查找系统环境变量,并读取其值作为当前配置项属于的值
         { 
             "db": {
                   "pwd": "APP_PWD"
             }
         }
        

        九.Ajsx

        它是浏览器提供的一套方法,可以实现页面无刷新更新数据,提高用户浏览网站应用的体验。

        1.运行原理、Ajax封装、模板引擎

        1. 创建ajax对象

           var xhr = new XMLHttpRequest();
          
        2. 告诉 Ajax 请求地址以及请求方式

          xhr.open('get', 'http://www.example.com');
          
        3. 发送请求

          xhr.send();
          
        4. 获取服务器端给与客户端的响应数据

           xhr.onload = function () {
               console.log(xhr.responseText);
           }
          

        服务端响应的数据格式

        在真实的项目中,服务器端大多数情况下会以 JSON对象作为响应数据的格式。当客户端拿到响应数据时,要将 JSON 数据和 HTML 字符串进行拼接,然后将拼接的结果展示在页面中。

        在 http 请求与响应的过程中,无论是请求参数还是响应内容,如果是对象类型,最终都会被转换为对象字符串进行传输。

        JSON.parse() // 将 json 字符串转换为json对象
        

        传递get请求参数

         <script type="text/javascript">
                // 获取按钮元素
                var btn = document.getElementById('btn');
                // 获取姓名文本框
                var username = document.getElementById('username');
                // 获取年龄文本框
                var age = document.getElementById('age');
                // 为按钮添加点击事件
                btn.onclick = function() {
                    // 创建ajax对象
                    var xhr = new XMLHttpRequest();
                    // 获取用户在文本框中输入的值
                    var nameValue = username.value;
                    var ageValue = age.value;
                    // 拼接请求参数
                    var params = 'username=' + nameValue + '&age=' + ageValue;
                    // 配置ajax对象
                    //get请求是不能提交json对象数据格式的
                    xhr.open('get', 'http://localhost:3000/get?' + params);
                    // 发送请求
                    xhr.send();
                    // 获取服务器端响应的数据
                    xhr.onload = function() {
                        console.log(xhr.responseText)
                    }
                }
            </script>
        

        传递post请求参数

         <script type="text/javascript">
                // 获取按钮元素
                var btn = document.getElementById('btn');
                // 获取姓名文本框
                var username = document.getElementById('username');
                // 获取年龄文本框
                var age = document.getElementById('age');
                // 为按钮添加点击事件
                btn.onclick = function() {
                    // 创建ajax对象
                    var xhr = new XMLHttpRequest();
                    // 获取用户在文本框中输入的值
                    var nameValue = username.value;
                    var ageValue = age.value;
                    // 拼接请求参数
                    var params = 'username=' + nameValue + '&age=' + ageValue;
                    // 配置ajax对象
                    xhr.open('post', 'http://localhost:3000/post');
                    // 设置请求参数格式的类型(post请求必须要设置)
                    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
                    // 发送请求
                    xhr.send(params);
                    // 获取服务器端响应的数据
                    xhr.onload = function() {
                        console.log(xhr.responseText)
                    }
                }
            </script>
        

        请求参数的格式

        1. application/x-www-form-urlencoded

           name=zhangsan&age=20&sex=男
          
        2. application/json

          {name: 'zhangsan', age: '20', sex: '男'}
        

        Ajax 状态码

        在创建ajax对象,配置ajax对象,发送请求,以及接收完服务器端响应数据,这个过程中的每一个步骤都会对应一个数值,这个数值就是ajax状态码。

        <script type="text/javascript">
                var xhr = new XMLHttpRequest();
                //状态码
                // 0 已经创建了ajax对象 但是还没有对ajax对象进行配置
                console.log(xhr.readyState);
                xhr.open('get', 'http://localhost:3000/readystate');
                // 1 已经对ajax对象进行配置 但是还没有发送请求
                console.log(xhr.readyState);
        
                // onreadystatechange事件 当ajax状态码发生变化的时候触发
                xhr.onreadystatechange = function() {
                    // 2 请求已经发送了
                    // 3 已经接收到服务器端的部分数据了
                    // 4 服务器端的响应数据已经接收完成
                    console.log(xhr.readyState);
                    // 对ajax状态码进行判断 如果状态码的值为4就代表数据已经接收完成了
                    if (xhr.readyState == 4) {
                        console.log(xhr.responseText);
                    }
                }
        
                xhr.send();
            </script>
        

        错误处理

        1. 网络畅通,服务器端能接收到请求,服务器端返回的结果不是预期结果。

        可以判断服务器端返回的状态码,分别进行处理。xhr.status 获取http状态码

        ​ 2.网络畅通,服务器端没有接收到请求,返回404状态码。

        检查请求地址是否错误。

        ​ 3.网络畅通,服务器端能接收到请求,服务器端返回500状态码。

        服务器端错误,找后端程序员进行沟通。

        ​ 4.网络中断,请求无法发送到服务器端。

        会触发xhr对象下面的onerror事件,在onerror事件处理函数中对错误进行处理

        低版本 IE 浏览器的缓存问题

        **问题:**在低版本的 IE 浏览器中,Ajax 请求有严重的缓存问题,即在请求地址不发生变化的情况下,只有第一次请求会真正发送到服务器端,后续的请求都会从浏览器的缓存中获取结果。即使服务器端的数据更新了,客户端依然拿到的是缓存中的旧数据。

        **解决方案:**在请求地址的后面加请求参数,保证每一次请求中的请求参数的值不相同。

        xhr.open('get', 'http://www.example.com?t=' + Math.random());
        

        Ajax封装

        发送一次请求代码过多,发送多次请求代码冗余且重复

        将请求代码封装到函数中,发请求时调用函数即可

         <script>
                function ajax(obj) {
                    //存储的是默认值
                    var defaults = {
                            type: 'get',
                            url: '',
                            date: {},
                            header: {
                                'Content-Type': 'application/x-www-form-urlencoded'
                            },
                            success: function() {},
                            error: function() {}
                        }
                        //使用obj对象中的属性覆盖defaults对象中的属性
                    Object.assign(defaults, obj);
        
                    //创建ajax对象
                    var xhr = new XMLHttpRequest()
                        //拼接请求参数的变量
                    var params = ''
                        //循环用户传递进来的对象格式参数
                    for (var attr in defaults.date) {
                        //将参数转换为字符串格式
                        params += attr + '=' + defaults.date[attr] + '&'
                    }
                    //将参数最后面的&截取掉,并重新赋值给params变量
                    params = params.substr(0, params.length - 1)
                        //判断请求方式
                    if (defaults.type == 'get') {
                        defaults.url = defaults.url + '?' + params
                    }
        
                    //配置ajax对象
                    xhr.open(defaults.type, defaults.url)
        
                    //如果请求方式是post
                    if (defaults.type == 'post') {
                        // 用户希望的向服务器端传递的请求参数的类型
                        var ContentType = defaults.header['Content-Type']
                            //设置请求参数格式的类型
                        xhr.setRequestHeader('Content-Type', ContentType)
                            // 判断用户希望的请求参数格式的类型
                            // 如果类型为json
                        if (ContentType == 'application/json') {
                            // 向服务器端传递json数据格式的参数
                            xhr.send(JSON.stringify(defaults.date))
                        } else {
                            // 向服务器端传递普通类型的请求参数
                            xhr.send(params)
                        }
                    } else {
                        xhr.send()
                    }
                    //监听xhr对象下面的onload事件
                    //当xhr对象接收完响应数据后触发
                    xhr.onload = function() {
                        // 获取响应头中的数据 xhr.getResponseHeader()
                        var contentType = xhr.getResponseHeader('Content-Type')
                            //服务器端返回的数据
                        var responseText = xhr.responseText
        
                        // 如果响应类型中包含applicaition/json
                        if (contentType.includes('application/json')) {
                            //将JSON字符串转换为JSON对象
                            responseText = JSON.parse(responseText)
                        }
                        // 当http状态码等于200的时候
                        if (xhr.status == 200) {
                            // 请求成功 调用处理成功情况的函数
                            defaults.success(responseText)
                        } else {
                            // 请求失败 调用处理失败情况的函数
                            defaults.error(responseText, xhr)
                        }
                    }
                }
        
                ajax({
                    //求情方式
                    type: 'get',
                    //请求地址
                    url: 'http://localhost:3000/responseData',
                    success: function(date) {
                        console.log('这里是success函数');
                        console.log(date);
                    },
                    error: function(date, xhr) {
                        console.log('这里是err函数' + date);
                        console.log(xhr);
        
                    }
                })
        
                /*
        			请求参数要考虑的问题
        				1.请求参数位置的问题
        					将请求参数传递到ajax函数内部, 在函数内部根据请求方式的不同将请求参数放置在不同的位置
        					get 放在请求地址的后面
        					post 放在send方法中
        
        				2.请求参数格式的问题
        					application/x-www-form-urlencoded
        						参数名称=参数值&参数名称=参数值
                                name=zhangsan&age=20
                                
        					application/json
                                {name: 'zhangsan', age: 20}
                                
        					1.传递对象数据类型对于函数的调用者更加友好
        					2.在函数内部对象数据类型转换为字符串数据类型更加方便
        		*/
            </script>
        

        模板引擎

        作用:使用模板引擎提供的模板语法,可以将数据和 HTML 拼接起来。

        官方地址:
        https://aui.github.io/art-template/zh-cn/index.html

        模板引擎使用步骤

         <!-- 1. 将模板引擎的库文件引入到当前页面 -->
            <script src="/js/template-web.js"></script> 
        
        <div id="container"></div>
        
            <!-- 2.准备art-template模板 -->
            <script type="text/html" id="tpl">
                <h1>{{username}} {{age}}</h1>
            </script>
            <script type="text/javascript">
                // 3.告诉模板引擎将那个数据和哪个模板进行拼接
                // 1) 模板id 2)数据 对象类型
                // 方法的返回值就是拼接好的html字符串
                var html = template('tpl', {
                    username: 'zhangsan',
                    age: 30
                });
                document.getElementById('container').innerHTML = html;
            </script>
        

        2.formData、同源跨域

        FormData 对象的作用

        1. 模拟HTML表单,相当于将HTML表单映射成表单对象,自动将表单对象中的数据拼接成请求参数的格式。
        2. 异步上传二进制文件

        FormData使用方法

         <!-- 创建普通的html表单 -->
            <form id="form">
                <input type="text" name="username">
                <input type="password" name="password">
                <input type="button" id="btn" value="提交">
            </form>
            <script type="text/javascript">
                // 获取按钮
                var btn = document.getElementById('btn');
                // 获取表单
                var form = document.getElementById('form');
                // 为按钮添加点击事件
                btn.onclick = function() {
                    // 将普通的html表单转换为表单对象
                    var formData = new FormData(form);
                    // 创建ajax对象
                    var xhr = new XMLHttpRequest();
                    // 对ajax对象进行配置
                    xhr.open('post', 'http://localhost:3000/formData');
                    // 发送ajax请求
                    xhr.send(formData);
                    // 监听xhr对象下面的onload事件
                    xhr.onload = function() {
                        // 对象http状态码进行判断
                        if (xhr.status == 200) {
                            console.log(xhr.responseText);
                        }
                    }
                }
            </script>
        
        //入口文件app.js
        const formidable = require('formidable');
        app.post('/formData', (req, res) => {
            // 创建formidable表单解析对象
            const form = new formidable.IncomingForm();
            // 解析客户端传递过来的FormData对象
            form.parse(req, (err, fields, files) => {
                res.send(fields);
            });
        });
        

        注意

        1. Formdata 对象不能用于 get 请求,因为对象需要被传递到 send 方法中,而 get 请求方式的请求参数只能放在请求地址的后面。
        2. 服务器端 bodyParser 模块不能解析 formData 对象表单数据,我们需要使用formidable模块进行解析。

        formData 对象的实例方法

        1. 获取表单对象中属性的值

           formData.get('key');
          
        2. 设置表单对象中属性的值

          formData.set('key', 'value');
          
        3. 删除表单对象中属性的值

          formData.delete('key');
          
        4. 向表单对象中追加属性值

          formData.append('key', 'value');
          

          注意:set 方法与 append 方法的区别是,在属性名已存在的情况下,set 会覆盖已有键名的值,append会保留两个值。

        formData二进制文件上传

        // 实现文件上传的路由
        app.post('/upload', (req, res) => {
            // 创建formidable表单解析对象
            const form = new formidable.IncomingForm();
            // 设置客户端上传文件的存储路径
            form.uploadDir = path.join(__dirname, 'public', 'uploads');
            // 保留上传文件的后缀名字
            form.keepExtensions = true;
            // 解析客户端传递过来的FormData对象
            form.parse(req, (err, fields, files) => {
                // 将客户端传递过来的文件地址响应到客户端
                res.send({
                    path: files.attrName.path.split('public')[1]
                });
            });
        });
        
         <div class="container">
                <div class="form-group">
                    <label>请选择文件</label>
                    <input type="file" id="file">
                    <div class="padding" id="box">
                        <!--<img src="" class="img-rounded img-responsive">-->
                    </div>
                    <div class="progress">
                        <div class="progress-bar" style="width: 0%;" id="bar">0%</div>
                    </div>
                </div>
            </div>
            <script type="text/javascript">
                // 获取文件选择控件
                var file = document.getElementById('file');
                // 获取进度条元素
                var bar = document.getElementById('bar');
                // 获取图片容器
                var box = document.getElementById('box');
                // 为文件选择控件添加onchanges事件
                // 在用户选择文件时触发
                file.onchange = function() {
                    // 创建空的formData表单对象
                    var formData = new FormData();
                    // 将用户选择的文件追加到formData表单对象中
                    formData.append('attrName', this.files[0]);
                    // 创建ajax对象
                    var xhr = new XMLHttpRequest();
                    // 对ajax对象进行配置
                    xhr.open('post', 'http://localhost:3000/upload');
                    // 在文件上传的过程中持续触发
                    xhr.upload.onprogress = function(ev) {
                            // ev.loaded 文件已经上传了多少
                            // ev.total  上传文件的总大小
                            var result = (ev.loaded / ev.total) * 100 + '%';
                            // 设置进度条的宽度
                            bar.style.width = result;
                            // 将百分比显示在进度条中
                            bar.innerHTML = result;
                        }
                        // 发送ajax请求
                    xhr.send(formData);
                    // 监听服务器端响应给客户端的数据
                    xhr.onload = function() {
                        // 如果服务器端返回的http状态码为200
                        // 说明请求是成功的
                        if (xhr.status == 200) {
                            // 将服务器端返回的数据显示在控制台中
                            var result = JSON.parse(xhr.responseText);
                            // 动态创建img标签
                            var img = document.createElement('img');
                            // 给图片标签设置src属性
                            img.src = result.path;
                            // 当图片加载完成以后
                            img.onload = function() {
                                // 将图片显示在页面中
                                box.appendChild(img);
                            }
                        }
                    }
        
                }
            </script>
        

        同源

        如果两个页面拥有相同的协议、域名和端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源

        同源政策是为了保证用户信息的安全,防止恶意的网站窃取数据。最初的同源政策是指
        A 网站在客户端设置的 Cookie,B网站是不能访问的。

        JSONP

        jsonp 是 json with padding 的缩写,它不属于 Ajax 请求,但它可以模拟 Ajax 请求

        //封装的JSONP方法
        function jsonp(options) {
            // 动态创建script标签
            var script = document.createElement('script');
            // 拼接字符串的变量
            var params = '';
        
            for (var attr in options.data) {
                params += '&' + attr + '=' + options.data[attr];
            }
        
            // myJsonp0124741
            var fnName = 'myJsonp' + Math.random().toString().replace('.', '');
            // 它已经不是一个全局函数了
            // 我们要想办法将它变成全局函数
            window[fnName] = options.success;
            // 为script标签添加src属性
            script.src = options.url + '?callback=' + fnName + params;
            // 将script标签追加到页面中
            document.body.appendChild(script);
            // 为script标签添加onload事件
            script.onload = function() {
                document.body.removeChild(script);
            }
        }
        

        CORS 跨域资源共享

        第三方插件cors 可实现跨域请求

        const cors = require('cors')
        app.use(cors())
        

        CORS:全称为 Cross-originresource sharing,即跨域资源共享,它允许浏览器向跨域服务器发送 Ajax 请求,克服了 Ajax 只能同源使用的限制。

        // 拦截所有请求
        app.use((req, res, next) => {
            // 1.允许哪些客户端访问我
            // * 代表允许所有的客户端访问我
            // 注意:如果跨域请求中涉及到cookie信息传递,值不可以为*号 比如是具体的域名信息
            res.header('Access-Control-Allow-Origin', 'http://localhost:3000')
                // 2.允许客户端使用哪些请求方法访问我
            res.header('Access-Control-Allow-Methods', 'get,post')
                // 允许客户端发送跨域请求时携带cookie信息
            res.header('Access-Control-Allow-Credentials', true);
            next();
        });
        

        withCredentials属性

        在使用Ajax技术发送跨域请求时,默认情况下不会在请求中携带cookie信息。

        withCredentials:指定在涉及到跨域请求时,是否携带cookie信息,默认值为false

        Access-Control-Allow-Credentials:true 允许客户端发送请求时携带cookie

           // 当发送跨域请求时,携带cookie信息
           xhr.withCredentials = true;
        

        第三方模块request

        // 向其他服务器端请求数据的模块request
        const request = require('request');
        app.get('/server', (req, res) => {
            request('http://localhost:3001/cross', (err, response, body) => {
                res.send(body);
            })
        });
        

        Jquery中的Ajax

        基本使用

          <script src="/js/jquery.min.js"></script>
            <script>
                $('#btn').on('click', function() {
                    $.ajax({
                        // 请求方式
                        type: 'post',
                        // 请求地址
                        url: '/base',
                        // 请求成功以后函数被调用
                        success: function(response) {
                            // response为服务器端返回的数据
                            // 方法内部会自动将json字符串转换为json对象
                            console.log(response);
                        },
                        // 请求失败以后函数被调用
                        error: function(xhr) {
                            console.log(xhr)
                        }
                    })
                });
            </script>
        

        传递请求参数

        //在 $.ajax({})中
        data: JSON.stringify(params),
              // 指定参数的格式类型
              contentType: 'application/json',
        

        beforeSend方法

        //在 $.ajax({})中  
        // 在请求发送之前调用
         beforeSend: function() {
            alert('请求不会被发送')
            // 请求不会被发送
            return false;
                        }
        

        serialize方法

        作用:将表单中的数据自动拼接成字符串类型的参数

        var params = $('#form').serialize();
        // name=zhangsan&age=30
        
          // 将表单中用户输入的内容转换为对象类型
                function serializeObject(obj) {
                    // 处理结果对象
                    var result = {};
                    // [{name: 'username', value: '用户输入的内容'}, {name: 'password', value: '123456'}]
                    var params = obj.serializeArray();
        
                    // 循环数组 将数组转换为对象类型
                    $.each(params, function(index, value) {
                            result[value.name] = value.value;
                        })
                        // 将处理的结果返回到函数外部
                    return result;
                }
        

        发送jsonp请求

        $.ajax({
            url: 'http://www.example.com',
            // 指定当前发送jsonp请求
            dataType: 'jsonp',
            // 修改callback参数名称
            jsonp: 'cb',
            // 指定函数名称
            jsonCallback: 'fnName',
            success: function (response) {} 
        })
        

        $.get

        作用: 用于发送get请求

        $.get('http://www.example.com', {name: 'zhangsan', age: 30}, function (response) {}) 
        

        $.post

        作用: 用于发送post请求

        $.post('http://www.example.com', {name: 'lisi', age: 22}, function (response) {})
        

        全局事件

           // 当页面中有ajax请求发送时触发
                $(document).on('ajaxStart', function() {
                    NProgress.start()
                })
        
          // 当页面中有ajax请求完成时触发
                $(document).on('ajaxComplete', function() {
                    NProgress.done()
                })
        

        RESTful 风格的API

        GETPOSTPUTDELETE
        获取数据添加数据更新数据删除数据

        XML基础

        XML是什么?

        XML 的全称是 extensible markup language,代表可扩展标记语言,它的作用是传输和存储数据。

        XML DOM

        XML DOM 即 XML 文档对象模型,是 w3c 组织定义的一套操作 XML 文档对象的API。浏览器会将 XML 文档解析成文档对象模型

         <button id="btn">发送请求</button>
            <div id="container"></div>
            <script type="text/javascript">
                var btn = document.getElementById('btn');
                var container = document.getElementById('container');
        
                btn.onclick = function() {
                    var xhr = new XMLHttpRequest();
                    xhr.open('get', '/xml');
                    xhr.send();
                    xhr.onload = function() {
                        // xhr.responseXML 获取服务器端返回的xml数据
                        var xmlDocument = xhr.responseXML;
                        var title = xmlDocument.getElementsByTagName('title')[0].innerHTML;
                        container.innerHTML = title;
                    }
                }
            </script>
        

        十.博客项目

        1.git

        Git是一个分布式版本管理控制系统(缩写VCS),它可以在任何时间点,将文档的状态作为更新记录保存起来,也可以在任何时间点,将更新记录恢复回来。

        • 安装完后,右键会出现git菜单,选中 Git Bash Here,弹出命令窗口
        • 输入命令 git --version 查看git版本

        git使用前配置

        1. 配置提交人姓名:git config --global user.name 提交人姓名
        2. 配置提交人姓名:git config --global user.email 提交人邮箱
        3. 查看git配置信息:git config --list

        git使用

        1. git init` 初始化git仓库
        2. git status 查看文件状态
        3. git add 文件列表 追踪文件
        4. git commit -m 提交信息 向仓库中提交代码
        5. git log 查看提交记录
        6. git checkout 文件 撤销,用暂存区中的文件覆盖工作目录中的文件
        7. git rm --cached 文件名 将文件从暂存区中删除
        8. git reset --hard 提交ID 恢复git仓库中指定版本的项目

        git分支

        • git branch 查看分支
        • git branch 分支名称 创建分支
          • 在哪条分支上输入的命令,就是在哪条分支上进行的创建
          • git branch develop -创建了一个develop的分支
        • git checkout 分支名称 切换分支
          • git checkout develop -切换到develop分支
          • 注意:当切换分支的时候,需要把暂存区里面的文件进行提交,不然会暂存区里面的文件会跟着到切换的这条分支上
          • 当切换会主分支的时候,就看不到其他分支里面的文件了
        • git merge 要合并进来的分名 合并分支
          • 如果当前分支的工作已经完成,就可以合并到到其他分支
          • 需要分清谁要合并谁,例如我们在开发分支上完成了功能,应该合并到主分支上,所以我们要站在主分支角度来进行合并
          • 虽然进行了合并,但是开发分支还是存在
        • git branch -d 分支名称 删除分支(分支被合并后才允许删除)(-D 强制删除)
          • 分支工作已经完成,就可以进行删除
          • git branch -d develop
          • 如果分支没有进行合并,那么默认是不能被删除,这是由于git有分支保护机制
          • 如果想强行删除,把-d 改成-D : git branch -D develop

        git暂时保存更改

        在git中,可以暂时提取分支上所有的改动并存储,让开发人员得到一个干净的工作副本,临时转向其他工作。

        • 存储临时改动: git stash
        • 恢复改动: git stash pop

        Github

        访问github首页,点击 Sign up 连接。(注册)

        1. git remote add 远程仓库地址别名 远程仓库地址

        2. git push -u 远程仓库地址或别名 本地分支名称:

          -u 记住推送地址及分支,下次推送只需要输入git push即可

        多人协作开发

        因为A已经创建了远程的仓库,所以程序员B就不需要创建仓库,直接把远程的仓库克隆一份到本地即可

        git clone 远程仓库地址
        

        A将远程仓库中的最新内容拉取到本地

        拉取利用pull命令,拉取是读操作,不需要校验身份

        git pull origin master
        

        git忽略清单

        将不需要被git管理的文件名字添加到此文件中,在执行git命令的时候,git就会忽略这些文件

        git忽略清单文件名称叫: .gitignore

        仓库的详细说明

        在仓库根目录添加一个 readme.md 文件即可,在里面写上内容,push到服务器后,默认在github里面就能看到仓库的详细说明了

        git相关命令整理

        git config --global user.name  //配置姓名
        git config --global user.email  //配置邮箱
        git config --list  //查看配置信息
        git init 	//初始化本地仓库
        git status 	 //查看文件状态
        git add 文件名 	//添加某个文件到暂存区,如果写 . 代表当前文件夹下所有的文件、
        git commit -m 日志说明   //提交到本地仓库
        git log    //查看提交记录
        git checkout 文件名    //撤销,让暂存区文件覆盖工作区间文件
        git rm --cached 文件名   	//在暂存区移除相应文件
        git reset --hard 提交ID  	//恢复到指定版本
        git branch      //查看分支
        git branch develop  //创建分支
        git checkout 分支名  //切换分支
        git merge  要合并的分支名//合并分支
        git branch -d 分支名称  //删除分支
        git clone 地址 //克隆远程仓库
        git push 地址 分支名  //往服务器推送
        git pull 地址  //将服务器代码拉取到本地
        git remote add 名称 地址 //给地址取别名
        git push -u origin 分支名  //把该分支推送到云端仓库
        ssh-keygen  //生成一对密钥
        

        十一.Vue

        1.指令

        v-cloak

        防止页面加载时出现闪烁问题

        <script type="text/css">
                [v - cloak] { display: none; }
        </script>
         <div id="app" v-cloak>
        </div>
        

        v-text

        • v-text指令用于将数据填充到标签中,作用于插值表达式类似,但是没有闪动问题
        • 如果数据中有HTML标签会将html标签一并输出
        • 注意:此处为单向绑定,数据对象上的值改变,插值会发生变化;但是当插值发生变化并不会影响数据对象的值
         <div v-text='msg'></div>
         <div v-text>{{msg}}</div>
        

        v-html

        • 用法和v-text 相似 但是他可以将HTML片段填充到标签中
        • 可能有安全问题, 一般只在可信任内容上使用 v-html永不用在用户提交的内容上
        • 它与v-text区别在于v-text输出的是纯文本,浏览器不会对其再进行html解析,但v-html会将其当html标签解析后输出。
         <div v-html='msg1'></div>
        

        v-pre

        • 显示原始信息跳过编译过程
        • 跳过这个元素和它的子元素的编译过程。
        • 一些静态的内容不需要编译加这个指令可以加快渲染
        <div v-pre>{{msg}}</div>
        

        v-once

        执行一次性的插值【当数据改变时,插值处的内容不会继续更新】

          <!-- 即使data里面定义了msg 后期我们修改了 仍然显示的是第一次data里面存储的数据即 Hello Vue.js  -->
             <span v-once>{{ msg}}</span>    
        <script>
            new Vue({
                el: '#app',
                data: {
                    msg: 'Hello Vue.js'
                }
            });
        </script>
        

        v-model

        双向数据绑定

        • 当数据发生变化的时候,视图也就发生变化
        • 当视图发生变化的时候,数据也会跟着同步变化

        v-model是一个指令,限制在 <input>、<select>、<textarea>、components中使用

         <div id="app">
              <div>{{msg}}</div>
              <div>
                  当输入框中内容改变的时候,  页面上的msg  会自动更新
                <input type="text" v-model='msg'>
              </div>
          </div>
        

        mvvm

        • MVC 是后端的分层开发概念; MVVM是前端视图层的概念,主要关注于 视图层分离,也就是说:MVVM把前端的视图层,分为了 三部分 Model, View , VM ViewModel
        • m model
          • 数据层 Vue 中 数据层 都放在 data 里面
        • v view 视图
          • Vue 中 view 即 我们的HTML页面
        • vm (view-model) 控制器 将数据和视图层建立联系
          • vm 即 Vue 的实例 就是 vm

        v-on

        • 用来绑定事件的
        • 形式如:v-on:click 缩写为 @click;
          <div>{{num}}</div>
                <button v-on:click='num++'>点击</button>
                <button @click='num++'>点击</button>
        <!-- 如果事件直接绑定函数名称,那么默认会传递事件对象作为事件函数的第一个参数 -->
        <!-- 2、如果事件绑定函数调用,那么事件对象必须作为最后一个参数显示传递,
              并且事件对象的名称必须是$event -->
                <button @click='handle(123,456,$event)'>点击1</button>
        

        事件修饰符

        <!-- 阻止单击事件继续传播 -->
        <a v-on:click.stop="doThis"></a>
        
        <!-- 提交事件不再重载页面 -->
        <form v-on:submit.prevent="onSubmit"></form>
        
        <!-- 修饰符可以串联   即阻止冒泡也阻止默认事件 -->
        <a v-on:click.stop.prevent="doThat"></a>
        
        <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
        <!-- 即事件不是从内部元素触发的 -->
        <div v-on:click.self="doThat">...</div>
        

        按键修饰符

        在做项目中有时会用到键盘事件,在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符

        <!-- 只有在 `keyCode`13 时调用 `vm.submit()` -->
        <input v-on:keyup.13="submit">
        
        <!-- -当点击enter 时调用 `vm.submit()` -->
        <input v-on:keyup.enter="submit">
        
        <!--当点击enter或者space时  时调用 `vm.alertMe()`   -->
        <input type="text" v-on:keyup.enter.space="alertMe" >
        
        常用的按键修饰符
        .enter =>    enter键
        .tab => tab键
        .delete (捕获“删除”和“退格”按键) =>  删除键
        .esc => 取消键
        .space =>  空格键
        .up =>.down =>.left =>.right =><script>
        	var vm = new Vue({
                el:"#app",
                methods: {
                      submit:function(){},
                      alertMe:function(){},
                }
            })
        
        </script>
        

        自定义修饰符别名

        在Vue中可以通过config.keyCodes自定义按键修饰符别名

        <div id="app">
            预先定义了keycode 116(即F5)的别名为f5,因此在文字输入框中按下F5,会触发prompt方法
            <input type="text" v-on:keydown.f5="prompt()">
        </div>
        
        <script>
        	
            Vue.config.keyCodes.f5 = 116;
        
            let app = new Vue({
                el: '#app',
                methods: {
                    prompt: function() {
                        alert('我是 F5!');
                    }
                }
            });
        </script>
        

        v-bind 属性绑定

        • v-bind 指令被用来响应地更新 HTML 属性
        • v-bind:href 可以缩写为 :href;
        <!-- 绑定一个属性 -->
        <img v-bind:src="imageSrc">
        
        <!-- 缩写 -->
        <img :src="imageSrc">
        

        分支结构 v-if

         <div id="app">
                <div v-if='score>90'>优秀</div>
                <div v-else-if='score>60'>良好</div>
                <div v-else>不及格</div>
                <br>
                <!-- v-show控制显示与隐藏 -->
                <div v-show='false'>v-show测试</div>
            </div>
            <script src="./js/vue.js"></script>
            <script>
                var lk = new Vue({
                    //el:元素挂载位置  data:模型数据(值是一个对象)
                    el: '#app',
                    data: {
                        score: 55
                    },
                    //函数要定义在methods中
                    methods: {
                        handle: function() {
                            this.url = 'https://cn.vuejs.org/v2/api/#v-on'
                        }
                    }
                })
            </script>
        

        v-show 和 v-if的区别

        • v-show本质就是标签display设置为none,控制隐藏
          • v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,故v-show性能更好一点。
        • v-if是动态的向DOM树内添加或者删除DOM元素
          • v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件

        循环结构 v-for

          <div id="app">
                <div>水果列表</div>
                <ul>
                    <li v-for='item in fruits'>{{item}}</li>
                </ul>
        
                <ul>
                    //:k的作用:帮助Vue区分不同的元素 从而提高性能
                    <li :key='index' v-for='(item,index) in fruits'>{{item+'----'+index}}</li>
                </ul>
            </div>
            <script src="./js/vue.js"></script>
            <script>
                var lk = new Vue({
                    //el:元素挂载位置  data:模型数据(值是一个对象)
                    el: '#app',
                    data: {
                        fruits: ['apple', 'orange', 'banana']
                    },
                    //函数要定义在methods中
                    methods: {
        
                    }
                })
            </script>
        
        • 不推荐同时使用 v-ifv-for
        • v-ifv-for 一起使用时,v-for 具有比 v-if 更高的优先级。

        key 的作用

        • key来给每个节点做一个唯一标识
        • key的作用主要是为了高效的更新虚拟DOM

        2.常用特性

        表单

        v-model

        1.单选

        <div>
           <span>性别:</span>
            <span>
                  <input type="radio" id="male" value="1" v-model='gender'>
                  <label for="male"></label>
                  <input type="radio" id="female" value="2" v-model='gender'>
                  <label for="female"></label>
            </span>
         </div>
        

        2.多选 – hobby 要定义成数组 否则无法实现多选

         <div>
                        <span>爱好:</span>
                        <input type="checkbox" id="ball" value="1" v-model='hobby'>
                        <label for="ball">篮球</label>
                        <input type="checkbox" id="sing" value="2" v-model='hobby'>
                        <label for="sing">唱歌</label>
                        <input type="checkbox" id="code" value="3" v-model='hobby'>
                        <label for="code">写代码</label>
                    </div>
        

        3.下拉框和文本

        		 <div>
                        <span>职业:</span>
                        <select v-model='occupation' multiple>
                  <option value="0">请选择职业...</option>
                  <option value="1">教师</option>
                  <option value="2">软件工程师</option>
                  <option value="3">律师</option>
                </select>
                    </div>
                    <div>
                        <span>个人简介:</span>
                        <textarea v-model='desc'></textarea>
                    </div>
        

        表单修饰符

        • .number 转换为数值
          • 注意点:
          • 当开始输入非数字的字符串时,因为Vue无法将字符串转换成数值
          • 所以属性值将实时更新成相同的字符串。即使后面输入数字,也将被视作字符串。
        • .trim 自动过滤用户输入的首尾空白字符
          • 只能去掉首尾的 不能去除中间的空格
        • .lazy 将input事件切换成change事件
          • .lazy 修饰符延迟了同步更新属性值的时机。即将原本绑定在 input 事件的同步逻辑转变为绑定在 change 事件上, 在失去焦点 或者 按下回车键时才更新
        <!-- 自动将用户的输入值转为数值类型 -->
        <input v-model.number="age" type="number">
        
        <!--自动过滤用户输入的首尾空白字符   -->
        <input v-model.trim="msg">
        
        <!-- 在“change”时而非“input”时更新 -->
        <input v-model.lazy="msg" >
        

        自定义指令

          Vue.directive('focus', {
                    inserted: function(el) {
                        // el表示指令所绑定的元素
                        el.focus();
                    }
                });
        

        自定义局部指令

         //自定义局部指定
                    directives: {
                        color: {
                            bind: function(el, binding) {
                                el.style.backgroundColor = binding.value.color
                            }
                        }
                    }
        

        计算属性 computed

         //计算属性,需要有返回值
                    computed: {
                        方法名: function() {
                            return 返回值
                        }
                    }
        //使用时直接写方法名 不需要跟括号
        

        侦听属性 watch

        • 使用watch来响应数据的变化
        • 一般用于异步或者开销较大的操作
        • watch 中的属性 一定是data 中 已经存在的数据
         		//侦听
                    watch: {
                        firstName: function(val) {
                          this.fullName = val + ' ' + this.lastName;
                        },
                        lastName: function(val) {
                          this.fullName = this.firstName + ' ' + val;
                        }
                    }
                });
        

        过滤器 filter

        过滤器三种使用方式

        	  <div>{{msg | upper}}</div>
                <div>{{msg | upper | lower}}</div>
                <div :abc='msg | upper'>测试数据</div>
        

        局部过滤器filters

         //过滤器
                    filters: {
                        upper: function(val) {
                            return val.charAt(0).toUpperCase() + val.slice(1);
                        }
                    }
        

        自定义过滤器filter

        Vue.filter(‘过滤器名称’,函数)

        
                 Vue.filter('upper', function(val) {
                  return val.charAt(0).toUpperCase() + val.slice(1);
                 });
        
        • Vue.js允许自定义过滤器,可被用于一些常见的文本格式化。
        • 过滤器可以用在两个地方:双花括号插值和v-bind表达式。
        • 过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示
        • 支持级联操作
        • 过滤器不改变真正的data,而只是改变渲染的结果,并返回过滤后的版本
        • 全局注册时是filter,没有s的。而局部过滤器是filters,是有s的

        生命周期

        常用的 钩子函数

        beforeCreate在实例初始化之后,数据观测和事件配置之前被调用 此时data 和 methods 以及页面的DOM结构都没有初始化 什么都做不了
        created在实例创建完成后被立即调用此时data 和 methods已经可以使用 但是页面还没有渲染出来
        beforeMount在挂载开始之前被调用 此时页面上还看不到真实数据 只是一个模板页面而已
        mountedel被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。 数据已经真实渲染到页面上 在这个钩子函数里面我们可以使用一些第三方的插件
        beforeUpdate数据更新时调用,发生在虚拟DOM打补丁之前。 页面上数据还是旧的
        updated由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。 页面上数据已经替换成最新的
        beforeDestroy实例销毁之前调用
        destroyed实例销毁后调用

        数组变异方法

        • 在 Vue 中,直接修改对象属性的值无法触发响应式。当你直接修改了对象属性的值,你会发现,只有数据改了,但是页面内容并没有改变
        • 变异数组方法即保持数组方法原有功能不变的前提下对其进行功能拓展
        push()往数组最后面添加一个元素,成功返回当前数组的长度
        pop()删除数组的最后一个元素,成功返回删除元素的值
        shift()删除数组的第一个元素,成功返回删除元素的值
        unshift()往数组最前面添加一个元素,成功返回当前数组的长度
        splice()有三个参数,第一个是想要删除的元素的下标(必选),第二个是想要删除的个数(必选),第三个是删除 后想要在原位置替换的值
        sort()sort() 使数组按照字符编码默认从小到大排序,成功返回排序后的数组
        reverse()reverse() 将数组倒序,成功返回倒序后的数组

        替换数组

        • 不会改变原始数组,但总是返回一个新数组
        filterfilter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
        concatconcat() 方法用于连接两个或多个数组。该方法不会改变现有的数组
        sliceslice() 方法可从已有的数组中返回选定的元素。该方法并不会修改数组,而是返回一个子数组

        动态数组响应式数据

        • Vue.set(a,b,c) 让 触发视图重新更新一遍,数据动态起来
        • a是要更改的数据 、 b是数据的第几项、 c是更改后的数据
          		 // Vue.set(vm.list, 2, 'lemon');
                vm.$set(vm.list, 1, 'lemon');
                // vm.info.gender = 'male';
                vm.$set(vm.info, 'gender', 'female');
        

        3.组件

        • 组件 (Component) 是 Vue.js 最强大的功能之一
        • 组件可以扩展 HTML 元素,封装可重用的代

        组件注册

        1.全局注册

        • Vue.component(‘组件名称’, { }) 第1个参数是标签名称,第2个参数是一个选项对象
        • 全局组件注册后,任何vue实例都可以用
        • 组件参数的data值必须是函数同时这个函数要求返回一个对象
        • 组件模板必须是单个根元素
        • 组件模板的内容可以是模板字符串
        //注册组件
        //如果使用驼峰式命名组件,那么在使用组件的时候,只能在字符串模板中用驼峰的方式使用组件,但是
        //在普通的标签模板中, 必须使用短横线的方式使用组件
                Vue.component('button-counter', {
                    //data必须是一个函数
                    data() {
                        return {
                            count: 0
                        }
                    },
                    //组件模板内容必须是单个跟元素
                    template: `
                    <button @click='handle'>点击了{{count}}次</button>
                    `,
                    methods: {
                        handle: function() {
                            this.count += 2
                        }
                    }
                })
        

        2.局部注册

          var vm = new Vue({
                    el: '#app',
                    data: {
        
                    },
                    //局部组件,局部组件只能在注册他的父组件中使用
                    components: {
                      'hello-world': {
                  		  data: function() {
                          return {
                            msg: 'HelloWorld'
                        }
                    },
                    template: '<div>{{msg}}</div>'
                };
                    }
                });
        

        组件传值

        • 父组件发送的形式是以属性的形式绑定值到子组件身上。
        • 然后子组件用属性props接收
        • 在props中使用驼峰形式,模板中需要使用短横线的形式字符串形式的模板中没有这个限制
         <div id="app">
                <div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div>
                <!-- 动态绑定父组件传值 -->
                <menu-item :title='dome' content='hellow' @enlarge-text='handle($event)'></menu-item>
            </div>
            <script type="text/javascript" src="js/vue.js"></script>
            <script type="text/javascript">
                Vue.component('menu-item', {
                    //props接收传递过来的值
                    props: ['title', 'content'],
                    data() {
                        return {
                            msg: '子组件'
                        }
                    },
                    template: `
                    <div>
                        <div>{{msg+'----'+title+'----'+content}}</div>
                        <button @click='$emit("enlarge-text",5)'>扩大父组件中字体大小					</button>
                    </div>
                    `
                })
                var vm = new Vue({
                    el: '#app',
                    data: {
                        pmsg: '父组件',
                        dome: '父组件传值',
                        fontSize: 10
                    },
                    methods: {
                        handle: function(val) {
                            // 扩大字体大小
                            this.fontSize += val;
                        }
                    }
                });
            </script>
        

        数据交互

        • 兄弟之间传递数据需要借助于事件中心,通过事件中心传递数据
          • 提供事件中心 var hub = new Vue()
        • 传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)
        • 接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名
        • 销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据
        <div id="app">
                <div>父组件</div>
                <div>
                    <button @click='handle'>销毁事件</button>
                </div>
                <test-tom></test-tom>
                <test-jerry></test-jerry>
            </div>
            <script type="text/javascript" src="js/vue.js"></script>
            <script type="text/javascript">
                //提供事件中心
                var hub = new Vue()
        
                Vue.component('test-tom', {
                    data() {
                        return {
                            num: 0
                        }
                    },
                    template: `
                    <div>
                        <div>TOM:{{num}}</div>
                        <div
                            <button @click='handle'>点击</button>
                        </div>
                    </div>
                    `,
                    methods: {
                        handle: function() {
                            //触发兄弟组件的事件
                            hub.$emit('jerry-event', 2)
                        }
                    },
                    mounted: function() {
                        // 监听事件
                        hub.$on('tom-event', (val) => {
                            this.num += val;
                        });
                    }
                })
        
                Vue.component('test-jerry', {
                    data() {
                        return {
                            num: 0
                        }
                    },
                    template: `
                    <div>
                        <div>JERRY:{{num}}</div>
                        <div
                            <button @click='handle'>点击</button>
                        </div>
                    </div>
                    `,
                    methods: {
                        handle: function() {
                            //触发兄弟组件的事件
                            hub.$emit('tom-event', 1)
                        }
                    },
                    mounted() {
                        //监听事件
                        hub.$on('jerry-event', (val) => {
                            this.num += val;
                        });
                    }
                })
        
                var vm = new Vue({
                    el: '#app',
                    data: {
        
                    },
                    methods: {
                        handle: function() {
                            //销毁事件
                            hub.$off('tom-event')
                            hub.$off('jerry-event')
                        }
                    }
                });
            </script>
        

        插槽

        <div id="app">
                <div>
                    <alert-box>bug</alert-box>
                    <alert-box>abc</alert-box>
                    <alert-box></alert-box>
        
                    <base-layout>
                        <p slot='header'>标题信息</p>
                        <!-- 使用template可插入多条 -->
                        <template slot='header'>
                            <p>标题信息1</p>
                        </template>
                        <p>主要内容1</p>
                        <template slot='footer'>
                <p>底部信息信息1</p>
              </template>
                    </base-layout>
                </div>
            </div>
        <script type="text/javascript" src="js/vue.js"></script>
        <script type="text/javascript">
                Vue.component('alert-box', {
                    //通过slot设置插槽
                    template: `
                    <div>
                    <strong>ERROR:</strong>
                        <slot>默认内容</slot>
                    </div>
                    `
                })
        
                //具名插槽
                Vue.component('base-layout', {
                    template: `
                <div>
                  <header>
                    <slot name='header'></slot>
                  </header>
                  <main>
                    <slot></slot>
                  </main>
                  <footer>
                    <slot name='footer'></slot>
                  </footer>
                </div>
              `
                });
        
                var vm = new Vue({
                    el: '#app',
                    data: {
        
                    },
                    methods: {
        
                    }
                });
            </script>
        

        作用域插槽

            <div id="app">
                <fruit-list :list='list'>
                    <!-- slotProps是自定义的名字 -->
                    <template slot-scope='slotProps'>
                        <strong  v-if='slotProps.info.id==2' class="current">{{slotProps.info.name}}</strong>
                        <span  v-else >{{slotProps.info.name}}</span>
                    </template>
                </fruit-list>
            </div>
            <script type="text/javascript" src="js/vue.js"></script>
            <script type="text/javascript">
                Vue.component('fruit-list', {
                    props: ['list'],
                    template: `
                    <div>
                      <li :key='item.id' v-for='item in list'><slot :info='item'>{{item.name}}</slot></li>
                    </div>
                    `
                })
                var vm = new Vue({
                    el: '#app',
                    data: {
                        list: [{
                            id: 1,
                            name: 'apple'
                        }, {
                            id: 2,
                            name: 'orange'
                        }, {
                            id: 3,
                            name: 'banana'
                        }]
                    },
                    methods: {
        
                    }
                });
            </script>
        

        4.Promise、fetch、axios、async

        Promise

          <script type="text/javascript">
            /*
             1. Promise基本使用
                   我们使用new来构建一个Promise  Promise的构造函数接收一个参数,是函数,并且传入两个参数:		   resolve,reject, 分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数
            */
        
        
            var p = new Promise(function(resolve, reject){
              //2. 这里用于实现异步任务  setTimeout
              setTimeout(function(){
                var flag = false;
                if(flag) {
                  //3. 正常情况
                  resolve('hello');
                }else{
                  //4. 异常情况
                  reject('出错了');
                }
              }, 100);
            });
            //  5 Promise实例生成以后,可以用then方法指定resolved状态和reject状态的回调函数 
            //  在then方法中,你也可以直接return数据而不是Promise对象,在后面的then中就可以接收到数据了  
            p.then(function(data){
              console.log(data)
            },function(info){
              console.log(info)
            });
          </script>
        

        基于Promise发送Ajax请求

         <script type="text/javascript">
            /*
              基于Promise发送Ajax请求
            */
            function queryData(url) {
             #   1.1 创建一个Promise实例
              var p = new Promise(function(resolve, reject){
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function(){
                  if(xhr.readyState != 4) return;
                  if(xhr.readyState == 4 && xhr.status == 200) {
                    # 1.2 处理正常的情况
                    resolve(xhr.responseText);
                  }else{
                    # 1.3 处理异常情况
                    reject('服务器错误');
                  }
                };
                xhr.open('get', url);
                xhr.send(null);
              });
              return p;
            }
        	# 注意:  这里需要开启一个服务 
            # 在then方法中,你也可以直接return数据而不是Promise对象,在后面的then中就可以接收到数据了
            queryData('http://localhost:3000/data')
              .then(function(data){
                console.log(data)
                #  1.4 想要继续链式编程下去 需要 return  
                return queryData('http://localhost:3000/data1');
              })
              .then(function(data){
                console.log(data);
                return queryData('http://localhost:3000/data2');
              })
              .then(function(data){
                console.log(data)
              });
          </script>
        

        Promise 基本AP

        .then()

        • 得到异步任务正确的结果

        .catch()

        • 获取异常信息

        .finally()

        • 成功与否都会执行(不是正式标准)
         <script type="text/javascript">
                function foo() {
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            // resolve(123);
                            reject('error');
                        }, 100);
                    })
                }
                // foo()
                //   .then(function(data){
                //     console.log(data)
                //   })
                //   .catch(function(data){
                //     console.log(data)
                //   })
                //   .finally(function(){
                //     console.log('finished')
                //   });
        
                // --------------------------
                // 两种写法是等效的
                foo()
                    .then(function(data) {
                        console.log(data)
                    }, function(data) {
                        console.log(data)
                    })
                    //.finally()成功与否都会执行(尚且不是正式标准)
                    .finally(function() {
                        console.log('finished')
                    });
            </script>
        

        Promise 静态方法

         //Promise.all()并发处理多个异步任务,所有任务都执行完成才能得到结果
                Promise.all([p1, p2, p3]).then(function(result) {
                       console.log(result)
                   })
        
                //Promise.race()并发处理多个异步任务,只要有一个任务完成就能得到结果
                Promise.race([p1, p2, p3]).then(function(result) {
                    console.log(result)
                })
        

        fetch

        • Fetch API是新的ajax解决方案 Fetch会返回Promise
        • fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象
        • fetch(url, options).then()
          fetch('http://localhost:3000/books', {
                        method: 'post',
                        body: JSON.stringify({
                            uname: '张三',
                            pwd: '456'
                        }),
                        headers: {
                            'Content-Type': 'application/json'
                        }
                    })
                    .then(function(data) {
                        //text()方法属于fetchAPI的一部分,它返回一个Promise实例对象,用于获取后台返回的数据
                        return data.text()
                    })
                    .then(function(data) {
                        console.log(data);
                    })
        

        fetchAPI 中 响应格式

        • 用fetch来获取数据,如果响应正常返回,我们首先看到的是一个response对象,其中包括返回的一堆原始字节,这些字节需要在收到后,需要我们通过调用方法将其转换为相应格式的数据,比如JSONBLOB或者TEXT等等
            /*
              Fetch响应结果的数据格式
            */
            fetch('http://localhost:3000/json').then(function(data){
              // return data.json();   //  将获取到的数据使用 json 转换对象
              return data.text(); //  //  将获取到的数据 转换成字符串 
            }).then(function(data){
              // console.log(data.uname)
              // console.log(typeof data)
              var obj = JSON.parse(data);
              console.log(obj.uname,obj.age,obj.gender)
            })
        

        axios

        • 基于promise用于浏览器和node.js的http客户端
        • 支持浏览器和node.js
        • 支持promise
        • 能拦截请求和响应
        • 自动转换JSON数据
        • 能转换请求和响应数据
         // axios put 请求传参
                axios.put('http://localhost:3000/axios/123', {
                    uname: 'lisi',
                    pwd: 123
                }).then(function(ret) {
                    console.log(ret.data)
                })
        

        axios 全局配置

         // 配置请求的基准URL地址
                axios.defaults.baseURL = 'http://localhost:3000/';
                // 配置请求头信息
                axios.defaults.headers['mytoken'] = 'hello';
        
                axios.get('axios-json').then(ret => {
                    console.log(ret.data.uname)
                })
        

        axios 拦截器

        • 请求拦截器
          • 请求拦截器的作用是在请求发送前进行一些操作
            • 例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易
        • 响应拦截器
          • 响应拦截器的作用是在接收到响应后进行一些操作
            • 例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页
         		 //请求拦截器
                axios.interceptors.request.use(function(config) {
                        console.log(config.url)
                        config.headers.mytoken = 'nihao';
                        return config;
                    }, function(err) {
                        console.log(err)
                    })
                    //响应拦截器
                axios.interceptors.response.use(function(res) {
                    // console.log(res)
                    var data = res.data;
                    return data;
                }, function(err) {
                    console.log(err)
                })
        

        async 和 await

        • async作为一个关键字放到函数前面
          • 任何一个async函数都会隐式返回一个promise
        • await关键字只能在使用async定义的函数中使用
          • ​ await后面可以直接跟一个 Promise实例对象
          • ​ await函数不能单独使用
        • async/await 让异步代码看起来、表现起来更像同步代码
         	# 1.  async 基础用法
            # 1.1 async作为一个关键字放到函数前面
        	async function queryData() {
              # 1.2 await关键字只能在使用async定义的函数中使用      await后面可以直接跟一个 Promise实例对象
              var ret = await new Promise(function(resolve, reject){
                setTimeout(function(){
                  resolve('nihao')
                },1000);
              })
              // console.log(ret.data)
              return ret;
            }
        	# 1.3 任何一个async函数都会隐式返回一个promise   我们可以使用then 进行链式编程
            queryData().then(function(data){
              console.log(data)
            })
        
        	#2.  async    函数处理多个异步函数
            axios.defaults.baseURL = 'http://localhost:3000';
        
            async function queryData() {
              # 2.1  添加await之后 当前的await 返回结果之后才会执行后面的代码   
              
              var info = await axios.get('async1');
              #2.2  让异步代码看起来、表现起来更像同步代码
              var ret = await axios.get('async2?info=' + info.data);
              return ret.data;
            }
        
            queryData().then(function(data){
              console.log(data)
            })
        

        5.路由、webpack

        **v-router ** --包含嵌套路由

        1.引入相关的库文件

        2.添加路由链接

        3.添加路由占位符(填充位)

        4.创建路由组件

        5.配置路由规则并创建路由实例

        6.挂载路由实例对象

         <!-- 1.引入相关的库文件 -->
            <script src="./lib/vue_2.5.22.js"></script>
            <script src="./lib/vue-router_3.0.2.js"></script>
        
         <div id="app">
                <!-- 2.添加路由链接 -->
                <router-link to="/user">User</router-link>
                <router-link to="/register">Register</router-link>
        
                <!-- 3.添加路由占位符(填充位) -->
                <router-view></router-view>
            </div>
         <script>
                // 4.创建路由组件
                const User = {
                        template: '<h1>User 组件</h1>'
                    }
                    //嵌套路由模板
                const Register = {
                    template: `<div>
                    <h1>Register 组件</h1>
                    <hr/>
                    <router-link to="/register/tab1">tab1</router-link>
                  <router-link to="/register/tab2">tab2</router-link>
                    <router-view />
                        </div>
                    `
                }
                const Tab1 = {
                    template: '<h3>tab1 子组件</h3>'
                }
                const Tab2 = {
                    template: '<h3>tab2 子组件</h3>'
                }
        
                // 5.配置路由规则并创建路由实例
                const router = new VueRouter({
                    // routes 是路由规则数组
                    routes: [{
                        //每个路由规则都是一个配置对象,其中至少包含 path 和 component 两个属性
                        path: '/user',
                        component: User
                    }, {
                        path: '/register',
                        component: Register,
                        //嵌套路由--通过chrldren 属性,为 /register 添加子路由规则
                        children: [{
                            path: '/register/tab1',
                            component: Tab1
                        }, {
                            path: '/register/tab2',
                            component: Tab2
                        }]
                    }, {
                        //redirect 表示将要被重定向的新地址
                        path: '/',
                        redirect: '/user'
                    }]
                })
        
                const vm = new new Vue({
                    el: '#app',
                    data: {},
                    // 6.挂载路由实例对象
                    // router: router
                    router
                })
            </script>
        

        动态路由

        <router-link to="/user/1">User1</router-link>
        
        const User = {
                    props: ['id', 'uname', 'age'], //使用proos接收路由参数
                    template: '<div> 用户id为:{{id}}--姓名为:{{uname}}--年龄为:{{age}}</div>'
                }
        
        // 创建路由实例对象
                const router = new VueRouter({
                    // 所有的路由规则
                    routes: [{
                        path: '/',
                        redirect: '/user/1'
                    }, {
                        path: '/user/:id',
                        component: User,
                        //如果 props 被设置为true, route.params 将会被设置为组件属性
                        // props: true
                        // props: { uname: 'lisi',age: 20}
        
                        //如果要传递id值  props的值应为函数类型
                        props: route => ({
                            uname: 'lisi',
                            age: 20,
                            id: route.params.id
                        })
                    }]
                })
        

        命名路由

        在配置路由规则并创建路由实例时,添加 name 属性来进行命名

          <!-- 使用命名路由 -->
                <router-link :to="{ name: 'user', params: {id: 3} }">User3</router-link>
        
        // 创建路由实例对象
                const router = new VueRouter({
                    // 所有的路由规则
                    routes: [{
                        // 命名路由
                        name: 'user',
                        path: '/user/:id',
                        component: User,
                        props: route => ({
                            uname: 'zs',
                            age: 20,
                            id: route.params.id
                        })
                    }]
                })
        

        编程式导航

        //跳转
        this.$router.push('/register')
        //后退
        this.$router.go(-1)
        

        webpack

        1.基本使用步骤

        ​ ①新建项目空白目录,并运行npm init -y 命令,初始化包管理配置文件package.json

        ​ ②新建 src 源代码目录

        ​ ③新建 src-> index.html 首页

        ​ ④初始化首页基本的结构

        ​ ⑤运行 npminstall jquery -S 命令,安装jQuery

        2.在项目中安装和配置webpack

        ​ ①运行 npminstall webpack webpack-cli -D 命令,安装webpack 相关的包

        ​ ②在项目根目录中,创建名为webpack.config.js 的 webpack 配置文件

        ​ ③在 webpack 的配置文件中,初始化如下基本配置:

        module.exports = {
        	//编译模式
            mode: 'development' //两种模式 development production
        }
        

        ​ ④ 在 package.json 配置文件中的scripts节点下,新增dev脚本如下:

        "scripts": {
        "dev": "webpack" // script 节点下的脚本,可以通过 npm run 名字 执行
        }
        

        ​ ⑤ 在终端中运行npm run dev 命令,启动webpack 进行项目打包。

        ​ 打包的入口文件为 src -> index.js

        ​ 打包的输出文件为 dist-> main.js

        3.配置打包的入口与出口

        ​ 如果要修改打包的入口与出口,可以在 webpack.config.js 中新增如下配置信息:

        const path = require('path')
        module.exports = {
           entry: path.join(__dirname, './src/index.js'), //打包入口文件的路径
            output: {
                path: path.join(__dirname, './dist'), // 输出文件的存放路径
                filename: 'bundle.js' // 输出文件的名称
            }
        }
        

        4.配置 webpack 的自动打包功能

        1.运行 npm install webpack-dev-server -D 命令,安装支持项目自动打包的工具

        2.修改 package.json -> scripts 中的 dev 命令如下:

        "scripts": {
        "dev": "webpack-dev-server" // script 节点下的脚本,可以通过 npm run 名字 执行
        }
        

        3.将 src -> index.html 中, script 脚本的引用路径, 修改为 “/buldle.js”

        4.运行 npm run dev 命令, 重新进行打包

        5.在浏览器中访问 http://localhost:8080 地址, 查看自动打包效果

        注意:

        webpack-dev-server会启动一个实时打包的http服务器

        webpack-dev-server打包生成的输出文件,默认放到了项目根目录中,而且是虚拟的、看不见的

        5.配置 html-webpack-plugin 生成预览页面

        1.运行 npm install html-webpack-plugin -D 命令, 安装生成预览页面的插件

        2.修改 webpack.config.js 文件头部区域, 添加如下配置信息:

            //导入生成预览页面的插件,得到一个构造函数
        const HtmlWebpackPlugin = require('html-webpack-plugin')
        const htmlPlguin = new HtmlWebpackPlugin({ //创建插件的实例对象
            template: './src/index.html', //指定要用到的模板文件
            filename: 'index.html' //指定生成的文件的名称,该文件存在于内存中,在目录中不显示
        })
        

        3.修改 webpack.config.js 文件向外暴露的配置对象, 新增如下配置节点:

        module.exports = {
            plugins: [htmlPlguin], //plugins数组是 webpack 打包期间会用到的一些插件列表
        }
        

        6.配置自动打包相关参数

        //package.json中的配置
        // --open 打包完成后自动打开浏览器
        // -- host 配置IP地址
        // --port 配置端口
        "scripts": {
        "dev": "webpack-dev-server --open --host 127.0.0.1 --port 8888" // script 节点下的脚本,可以通过 npm run 名字 执行
        }
        

        webpack加载器 --通过loader打包非js模块

        1.打包处理css文件

        1.运行 npm install style-loader css-loader -D 安装处理css文件的loader

        2.在 webpack.config.js 的module -> rules 数组中, 添加 loader 规则如下:

        module: {
                rules: [
         //test 表示匹配的文件类型, use 表示对应要调用的loader,并且use数组中loader顺序是固定的
                    { test: /\.css$/, use: ['style-loader', 'css-loader'}  ]
            }
        

        2.打包处理less文件

        1.运行 npm install less-loader less -D

        2.在 webpack.config.js 的module -> rules 数组中, 添加 loader 规则如下:

        module: {
                rules: [
         //test 表示匹配的文件类型, use 表示对应要调用的loader,并且use数组中loader顺序是固定的
             { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }  ]
            }
        

        3.打包处理scss文件

        1.运行 npm install sass-loader node-sass -D

        2.在 webpack.config.js 的module -> rules 数组中, 添加 loader 规则如下:

        module: {
                rules: [
         //test 表示匹配的文件类型, use 表示对应要调用的loader,并且use数组中loader顺序是固定的
            { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }  ]
            }
        

        4.配置postCss自动添加css的兼容前缀

        1.运行 npm install postcss-loader autoprefixer -D

        2.在项目根目录中创建 postcss 的配置文件, postcss.config.js, 并初始化如下配置:

        const autoprefixer = require('autoprefixer')
        module.exports = {
            plugins: [autoprefixer] //挂载插件
        }
        

        3.在 webpack.config.js 的module -> rules 数组中, 修改css的 loader 规则如下:

        module: {
                rules: [
         //test 表示匹配的文件类型, use 表示对应要调用的loader,并且use数组中loader顺序是固定的
          { test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader'] }  ]
            }
        

        5.打包样式表中的图片和字体文件

        1.运行 npm install url-loader file-loader -D

        2.在 webpack.config.js 的module -> rules 数组中, 添加 loader 规则如下:

        module: {
                rules: [
         //test 表示匹配的文件类型, use 表示对应要调用的loader,并且use数组中loader顺序是固定的
        { test: /\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/, use: 'url-loader?limit=16941' }  ]
            }
        

        其中 ? 之后的是 loader的参数项

        limit用来指定图片的大小,单位是字节(byte),只有小于 limit大小的图片,才会被转为base64图片

        6.打包处理js文件中的高级语法

        1.安装babel转换器相关的包: npm install babel-loader @babel/core @babel/runtime -D

        2.安装babel语法插件相关的包: npm install @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties -D

        3.在项目根目录中, 创建 babel 配置文件 babel.config.js 并初始化基本配置如下:

        module.exports = {
          presets: ['@babel/preset-env'],
          plugins: ['@babel/plugin-transform-runtime', '@babel/plugin-proposal-class-properties']
        }
        
        

        4.在 webpack.config.js 的module -> rules 数组中, 添加 loader 规则如下:

        module: {
                rules: [
        //exclude为排除项,表示 babel-loader 不需要处理的js文件
         { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }  ]
            }
        

        7.配置vue组件加载器

        1.运行 npm install vue-loader vue-template-compiler -D

        2.在 webpack.config.js 的module -> rules 数组中, 添加 vue-loader 的配置如下:

        const VueLoaderPlugin = require('vue-loader/lib/plugin')
        module.exports = {
          //plugins数组是 webpack 打包期间会用到的一些插件列表
            plugins: [htmlPlguin, new VueLoaderPlugin()], 
            module: {
                rules: [
        //test 表示匹配的文件类型, use 表示对应要调用的loader,并且use数组中loader顺序是固定的
                 { test: /\.vue$/, use: 'vue-loader' }
                ]
            }
        }
        

        8.在webpack项目中使用vue

        1.运行 npm install vue -S 安装vue

        2.在 src -> index.js 入口文件中, 通过 import Vue from ‘vue’ 来导入 vue 构造函数

        3.创建 vue 的实例对象, 并指定要控制的 el 区域

        4.通过 render 函数渲染App 根组件

        // 1.导入 Vue 构造函数
        import Vue from 'vue'
        // 2.导入单App根组件
        import App from './components/App.vue'
        
        const vm = new Vue({
        // 3.指定 vm 实例要控制的页面区域
            el: '#app',
        // 4.通过 render 函数, 把指定的组件渲染到 el 区域中
            render: h => h(App)
        })
        

        9.webpack 打包发布

        上线之前需要通过webpack将应用进行整体打包,可以通过 package.json 文件配置打包命令:

         //在package.json文件中配置 webpack 打包命令
         //该命令默认加载项目根目录中的 webpack.config.js 配置文件
        "scripts": {
          		  //用于开发调试的命令
                "dev": "webpack-dev-server --open --host 127.0.0.1 --port 8888",
                  //用于打包的命令
                "build": "webpack -p"
            }
        

        6.脚手架、组件库卡element-ui、项目配置

        Vue 脚手架用于快速生成 Vue 项目基础架构,其官网地址为:https://cli.vuejs.org/zh/

        安装3.x版本的Vue脚手架: npm install -g @vue/cli

        基于3.x版本的脚手架创建vue项目

        //1.基于 交互命令行 的方式,创建新版vue项目
        vue create 项目名(自定义)
        
        //2.基于 图形化界面 的方式,创建新版vue项目
        vue ui
        
        //3.基于 2.x 的旧模板,创建旧版vue项目
        npm install -g @vue/cli-init
        vue init webpack my-project
        

        Vue脚手架自定义配置

        1.在项目的根目录创建文件 vue.config.js

        2.在该文件中进行相关配置,从而覆盖默认配置

        //vue.config.js
        module.exports = {
            devServer: {
                // 自动打开浏览器
                open: true,
              	//配置默认端口号
                port: 8878
            }
        }
        

        Element-UI

        官网为: https://element.eleme.cn/#/zh-CN --桌面端组件库

        1.基于命令行方式手动安装

        1.安装依赖包 npm install element-ui -S

        2.导入 Element-UI 相关资源

        //手动配置 element-ui
        //导入组件库
        import ElementUI from 'element-ui'
        //导入组件相关样式
        import 'element-ui/lib/theme-chalk/index.css'
        //配置 Vue 插件
        Vue.use(ElementUI)
        

        2.基于图形化界面自动安装

        1.运行 vue ui 打开图形化界面

        2.通过Vue项目管理器,进入具体的项目配置面板

        3.点击 插件 -> 添加插件,进入插件查询面板

        4.搜索 vue-cli-plugin-element 并安装

        5.配置插件,实现按需导入,从而减少打包后项目的体积

        树形表格插件 --vue-table-with-tree-grid

        //在main.js中
        import TreeTable from 'vue-table-with-tree-grid'
        Vue.component('tree-table', TreeTable)
        

        富文本编辑器插件 --vue-quill-editor

        //在main.js中
        //导入富文本编辑器
        import VueQuillEditor from 'vue-quill-editor'
        //导入富文本编辑器对应的样式
        import 'quill/dist/quill.core.css'
        import 'quill/dist/quill.snow.css'
        import 'quill/dist/quill.bubble.css'
        //将富文本编辑器注册为全局可用组件
        Vue.use(VueQuillEditor)
        

        统计图插件 --echarts

         //1.导入 echarts
            import echarts from 'echarts'
         <!-- 2.为ECharts准备一个具备大小(宽高)的Dom -->
         <div id="main" style="width: 700px;height:400px;"></div>
         // 3.基于准备好的dom,初始化echarts实例
             var myChart = echarts.init(document.getElementById('main'));
          // 4.指定图表的配置项和数据
             const result = _.merge(res.data, this.options)
            //5.展示数据
             myChart.setOption(result)
        

        深拷贝插件 --lodash

          import _ from 'lodash'
         _.merge(res.data, this.options)
        

        进度条插件 --nprogerss

        //在main.js中
        //导入进度条对应的js和css
        import NProgress from 'nprogress'
        import 'nprogress/nprogress.css'
            //在request拦截器中,展示进度条 NProgress.start()
        axios.interceptors.request.use(config => {
                NProgress.start()
                config.headers.Authorization = window.sessionStorage.getItem('token')
                    // 在最后必须 return config
                return config
            })
            //在response拦截器中,隐藏进度条 NProgress.done()
        axios.interceptors.response.use(config => {
            NProgress.done()
            return config
        })
        

        去除console插件 --balel-plugin-transform-remove-console

        //在babel.config.js文件里的中
        //这是项目发布阶段需要用到的babel插件
        const prodPlugins = []
        if (process.NODE_ENV === 'production') {
          prodPlugins.push('transform-remove-console')
        }
        //"plugins"数组中,插入
        ...prodPlugins
        

        修改webpack的默认配置

        默认情况下,vue-cli 3.0生成的项目,隐藏了webpack配置项,如果我们需要配置webpack
        需要通过vue.config.js来配置。
        在项目根目录中创建vue.config.js文件,

        module.exports = {
            chainWebpack:config=>{
                //发布模式
                config.when(process.env.NODE_ENV === 'production',config=>{
                    //entry找到默认的打包入口,调用clear则是删除默认的打包入口
                    //add添加新的打包入口
                    config.entry('app').clear().add('./src/main-prod.js')
                })
                //开发模式
                config.when(process.env.NODE_ENV === 'development',config=>{
                    config.entry('app').clear().add('./src/main-dev.js')
                })
            }
        }
        

        补充:
        chainWebpack可以通过链式编程的形式,修改webpack配置
        configureWebpack可以通过操作对象的形式,修改webpack配置

        通过externals加载外部CND资源

        //在vue.config.js文件中,放在chainWebpack开发者模式中
         config.set('externals', {
                vue: 'Vue',
                'vue-router': 'VueRouter',
                axios: 'axios',
                lodash: '_',
                echarts: 'echarts',
                nprogress: 'NProgress',
                'vue-quill-editor': 'VueQuillEditor'
              })
            })
        //然后在index.html的头部区域中,通过CDN加载js和css样式
            <% if(htmlWebpackPlugin.options.isProd){ %>
          <!-- nprogress 的样式表文件 -->
          <link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" />
          <!-- 富文本编辑器 的样式表文件 -->
          <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.core.min.css" />
          <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.snow.min.css" />
          <link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.bubble.min.css" />
          <script src="https://cdn.staticfile.org/vue/2.5.22/vue.min.js"></script>
          <script src="https://cdn.staticfile.org/vue-router/3.0.1/vue-router.min.js"></script>
          <script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
          <script src="https://cdn.staticfile.org/lodash.js/4.17.11/lodash.min.js"></script>
          <script src="https://cdn.staticfile.org/echarts/4.1.0/echarts.min.js"></script>
          <script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
          <!-- 富文本编辑器的 js 文件 -->
          <script src="https://cdn.staticfile.org/quill/1.3.4/quill.min.js"></script>
          <script src="https://cdn.jsdelivr.net/npm/vue-quill-editor@3.0.4/dist/vue-quill-editor.js"></script>
          <% } %>
        

        通过CDN优化ElementUI的打包

        1.在main-prod.js中,注释掉element-ui按需加载的代码

        2.在index.html的头部区域中,通过CDN加载element-ui的js和css样式

         <!-- element-ui 的样式表文件 -->
          <link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.8.2/theme-chalk/index.css" />
        <!-- element-ui 的 js 文件 -->
          <script src="https://cdn.staticfile.org/element-ui/2.8.2/index.js"></script>
        

        路由懒加载

        1.安装 @babel/plugin-syntax-dynamic-import

        2.在babel.config.js配置文件中声明该插件

        //在"plugins"数组中
        '@babel/plugin-syntax-dynamic-import'
        

        3.将路由改为按需加载的形式

        //注:webpackChunkName后面为分组名字,最后面是该组件路径
        // import Cate from './components/goods/Cate.vue'
        const Cate = () => import(/* webpackChunkName: "Cate_Params" */ './components/goods/Cate.vue')
        // import Params from './components/goods/Params.vue'
        const Params = () => import(/* webpackChunkName: "Cate_Params" */ './components/goods/Params.vue')
        
        

        项目上线配置

        1.创建一个新文件夹 运行 npm init -y 初始化

        2.运行 npm install express

        3.把build的dist文件夹复制到该文件夹内

        4.创建app.js入口文件, 配置如下: 然后用node服务器运行该入口文件

        const express = require('express')
        const app = express()
        app.use(express.static('./dist'))
        app.listen(80, () => {
          console.log('server running at http://127.0.0.1');
        })
        

        5.开启gzip配置运行 npm install compression -D

        //在app.js中
        //网络传输压缩
        const compression = require('compression')
        //这行代码一定要写到静态资源托管之前
        app.use(compression())
        

        6.使用pm2管理应用,安装 npm install pm2 -g

        使用pm2启动项目,在终端中输入命令:pm2 start app.js --name 自定义名称
        查看项目列表命令:pm2 ls
        重启项目:pm2 restart 自定义名称
        停止项目:pm2 stop 自定义名称
        删除项目:pm2 delete 自定义名称

        7.Vuex

        Vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间的数据共享

        使用Vuex管理数据的好处:
        A.能够在vuex中集中管理共享的数据,便于开发和后期进行维护
        B.能够高效的实现组件之间的数据共享,提高开发效率
        C.存储在vuex中的数据是响应式的,当数据发生改变时,页面中的数据也会同步更新

        Vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间的数据共享

        使用Vuex管理数据的好处:
        A.能够在vuex中集中管理共享的数据,便于开发和后期进行维护
        B.能够高效的实现组件之间的数据共享,提高开发效率
        C.存储在vuex中的数据是响应式的,当数据发生改变时,页面中的数据也会同步更新

        Vuex基本使用

        1.安装 npm install vuex --save

        2.导入vuex包

        //在store文件夹或者store.js中
        import Vuex from 'vuex'
        Vue.use(Vuex)
        

        3.创建store对象

        //在store文件夹或者store.js中
        const store = new Vuex.Store({
        //state 中存放的就是全局共享的数据
          state: { count:0 }
        })
        

        4.将store对象挂载到vue实例中

        new Vue({
        	el:'#app',
          	render:h => h(app),
          	router,
          //将创建的共享数据对象,挂载到Vue实例中
          //所有的组件,就可以直接从store 中获取全局的数据了
          store
        })
        

        组件访问State数据

        State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储

        方法一: this.$store.state.数据名 --在< template >中可省略 this.

        方法二:

        <h3>当前最新的count值为:{{count}}</h3>
        <script>
          import { mapState } from 'vuex'
        
          export default {
            computed: {
              ...mapState(['count'])
            }
          }
        </script>
        

        Mutation

        Mutation用于修改变更$store中的数据,并且只能通过mutation变更Store数据,不可以直接操作Store中的数据

        使用方法一:

        //在store.js
        mutations: {
            add(state,step){
              //第一个形参永远都是state也就是$state对象
              //第二个形参是调用add时传递的参数
              state.count+=step;
            }
          }
        
        //在调用的文件中
        methods:{
          Add(){
            //使用commit函数调用mutations中的对应函数,
            //第一个参数就是我们要调用的mutations中的函数名
            //第二个参数就是传递给add函数的参数
            this.$store.commit('add',10)
          }
        }
        

        使用方法二:

        <button @click='sub(10)'>-1</button>
        <script>
          import { mapState, mapMutations } from 'vuex'
        
          export default {
            computed: {
              ...mapState(['count'])
            },
            methods: {
              //获得mapMutations映射的sub函数
              ...mapMutations(['sub'])
            }
          }
        </script>
        

        Action

        在mutations中不能编写异步的代码,会导致vue调试器的显示出错。
        在vuex中我们可以使用Action来执行异步操作。

        方法一:

        //在store.js中
         mutations: {
            jia (state) {
              //变更状态
              state.count += 1
            }
          },
          actions: {
            //来执行异步操作,不能直接修改state中的数据
            addAsync (context) {//若传递有参数 (context, nn) 
              setTimeout(() => {
                context.commit('jia')
              }, 1000)
            }
            
        //在要使用的文件的methods方法中定义,然后调用dome1函数即可
             dome1() {
                this.$store.dispatch('addAsync')//若传递有参数 ('addAsync',5)
              }
        

        方法二:

        //在store.js中同上
        
        <button @click='调用的函数名'>-1</button>
        //在要使用的文件的methods方法中
        import {mapActions} from 'vuex'
        methods:{
          ...mapActions(['调用的函数名'])
        }
        

        Getter

        Getter用于对Store中的数据进行加工处理形成新的数据
        它只会包装Store中保存的数据,并不会修改Store中保存的数据,当Store中的数据发生变化时,Getter生成的内容也会随之变化

        使用方法一: this.$store.getters.名称

        使用方法二:

        import { mapGetters } from 'vuex'
        computed:{
          ...mapGetters(['调用名称'])
        }
        

        十二.微信小程序

        下载微信开发者工具 https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

        1.UI组件、样式、json配置、生命周期

        text文本

        属性名类型默认值说明
        selectableBooleanfalse文本是否可选,除了text组件外,其他组件都无法长按选中
        spaceStringfalse显示连续空格,可选值:ensp、emsp、nbsp
        decodeBooleanfalse是否解码,可解析:&nbsp、&lt、&gt、&amp、&apos、&ensp、&emsp

        view视图容器

        属性名类型默认值说明
        hover-classStringnone指定按下去的样式类,当值为none时,没有点击效果
        hover-stop-propagationBooleanfalse指定是否阻止本节点的父节点出现点击态
        hover-start-timeNumber50按住后多久出现点击状态,单位毫秒
        hover-stay-timeNumber40手指松开后点击态保留时间,单位毫秒

        button按钮

        属性名类型默认值说明
        sizeStringdefault按钮大小
        typeStringdefault按钮的样式类型: primary, warn
        plainBooleanfalse按钮是否镂空,背景透明色
        disabledBooleanfalse是否禁用
        loadingBooleanfalse名称前是否带loading图标

        input输入框

        属性名类型默认值说明
        valueString输入框的初始内容
        typeString‘text’input的类型:text,number,idcard(身份证),digit(带小数点的数字)
        passwordBooleanfalse是否是密码类型
        placeholderString输入框为空时的占位符
        disabledBooleanfalse是否禁用
        maxlengthNumber140最大输入长度,值为-1时不限制最大长度

        image图片

        1.scr:支持本地和网络上的图片

        2.mode:指定图片裁剪、缩放的模式,image组件默认宽300px、高225px

        WXSS

        WXSS(WeiXin Style Sheets)是一套样式语言,用来决定 WXML 的组件应该怎么显示

        rpx

        rpx(responsive pixel):是微信小程序独有的、解决屏幕自适应的尺寸单位

        1.可以根据屏幕宽度进行自适应。不论大小屏幕,规定屏幕宽为750rpx。

        2.通过rpx设置元素和字体的大小,小程序在不同尺寸的屏幕上,可以实现自动适配

        @import 样式导入

        使用@import 可以导入外联样式表

        语法: @import ‘wxss样式表的相对路径’;

        app.json配置文件的作用

        小程序根目录下的 app.json 文件用来对微信小程序进行全局配置,它决定了页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等

        ​ page 数组:配置小程序的页面路径

        ​ window 对象:用于设置小程序的状态栏、导航条、标题、窗口背景颜色

        ​ tabBar 对象:配置小程序的tab栏效果,只能配置最少2个,最多5个tab标签,当渲染顶部tabBar时,不显示icon,只显示文本

        window节点常用的配置项

        属性名类型默认值说明
        navigationBarTitleTexString字符串导航栏标题文字内容
        navigationBarBackgroundColoHexColor#000000导航栏背景颜色,只接收16进制
        navigationBarTextStyleStringwhite导航栏标题颜色,仅支持black/white
        backgroundColorHexColor#ffffff下拉时窗口的背景颜色,只接收16进制
        backgroundTextStyleStringdark下拉loading的样式,仅支持dark/light
        enablePullDownRefreshBooleanfalse是否全局开启下拉刷新
        onReachBottomDistanceNumber50页面上拉触底时间触发时距页面底部距离,单位px

        tabBar 的组成部分

        background:导航条背景色

        selectedlconPath:选中时的图片路径

        borderStyle:tabBar上边框的颜色

        iconPath:未选中时的图片

        属性类型必填默认值描述
        colorHexColortab上的文字默认颜色
        selectedColorHexColortab上的文字选中时的颜色
        backgroundColorHexColortab的背景
        borderStyleStringblacktabBar上边框的颜色
        listArraytab的列表,最少2个、最多5个
        positionArraybottombabBar的位置,仅支持bottom/top

        list的配置项如下:

        属性类型必填描述
        pagePathString页面路径,必须在 pages 中先定义
        textStringtab 上按钮文字
        iconPathString图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。当 position 为 top 时,不显示 icon
        selectedIconPathString选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。当 position 为 top 时,不显示 icon

        page.json配置列表

        属性类型默认值描述
        navigationBarBackgroundColorHexColor#000000导航栏背景颜色,如 #000000
        navigationBarTextStyleStringwhite导航栏标题颜色,仅支持 black / white
        navigationBarTitleTextString导航栏标题文字内
        backgroundColorHexColor窗口的背景色
        backgroundTextStyleString#ffffff下拉 loading 的样式,仅支持 dark / light
        enablePullDownRefreshBooleanfalse是否开启当前页面下拉刷新
        onReachBottomDistanceNumber50页面上拉触底事件触发时距页面底部距离,单位为px
        disableScrollBooleanfalse设置为 true 则页面整体不能上下滚动。只在页面配置中有效,无法在 app.json 中设置

        生命周期

        1.应用生命周期:特指小程序从启动 -> 运行 -> 销毁的过程

        2.页面生命周期:特指小程序中,每个页面的加载 -> 渲染 -> 销毁的过程

        其中,页面的生命周期范围较小,应用程序的生命周期范围较大

        应用生命周期函数

        app.js是小程序执行的入口文件,在app.js中必须调用App()函数,且只能调用一次。其中,App()函数是用来注册并执行小程序的。

        App(Object)函数接收一个Object参数,可以通过这个Object参数,指定小程序的生命周期函数。

        例如:

        App({
          // 小程序初始化完成时,执行此函数,可以做一些初始化的工作。
          onLaunch: function(options) {},
          // 小程序显示到屏幕上的时候,执行此函数。
          onShow  : function(options) {},
          // 小程序被最小化的时候,执行此函数。
          onHide  : function() {}
        })
        

        页面生命周期函数

        每个小程序页面,必须拥有自己的.js文件,且必须调用 Page() 函数,否则报错。其中Page()函数用来注册小程序页面。

        Page(Object) 函数接收一个Object参数,可以通过这个Object参数,指定页面的生命周期函数。

        例如:

        Page({
          onLoad  : function(options) {}, // 监听页面加载
          onShow  : function() {},        // 监听页面显示
          onReady : function() {},        // 监听页面初次渲染完成
          onHide  : function() {},        // 监听页面隐藏
          onUnload: function() {}         // 监听页面卸载
        })
        

        2.绑定、脚本、页面操作

        数据绑定

        小程序中每个页面,由4部分组成,其中 .js 文件内可以定义页面的数据、生命周期函数、其它业务逻辑;

        如果要在.js文件内定义页面的数据,只需把数据定义到 data 节点下即可;

        示例代码如下:

        Page({
          data: {
            info: 'init data', // 字符串类型的数据
            array: [{msg: '1'}, {msg: '2'}] // 数组类型的数据
          }
        })
        

        Mustache语法

        把data中的数据绑定到页面中渲染,使用Mustache 语法(双大括号)将变量包起来即可;

        语法格式为: <view>{{ 要绑定的数据名称 }}</view>

        绑定属性

        页面结构: <view id="item-{{id}}"> </view>

        页面数据:

        Page({
          data: {
            id: 0
          }
        })
        

        bindtap绑定触摸事件

        1.通过 bindtap,可以为组件绑定触摸事件,语法如下:

        <view bindtap=“tapName”> Click me! <view>
        

        2.在相应的Page定义中写上相应的事件处理函数,事件参数是event

        Page({
          inputName: function(event) {
            console.log(event)
          }
        })
        

        bindinput绑定文本框输入事件

        1.通过 bindinput,可以为文本框绑定输入事件,语法如下

        <input bindinput=“inputName”><input>
        

        2.在相应的Page定义中写上相应的事件处理函数,事件参数是event

        Page({
          inputName: function(event) {
            console.log(event)
          }
        })
        

        data与文本框直接数据同步

        通过 this.setData(dataObject) 方法,可以给页面中的data数据重新赋值

        inputName: function (event) {
        	this.setData({
        	msg: event.detail.value // 为 data 中的 msg 重新赋值
        	})
        }
        

        事件传参

        1.不能在绑定事件的同时传递参数

        2.通过 data-*自定义属性传参,如下:

        //其中,info 会被当作参数名,数值 123 会被当作参数值。
        <button bindtap='btnHandler’ data-info={{123}}>事件传参</button>
        

        3.通过事件参数 event.target.dataset.参数名,能够获取data-*自定义属性传递到事件处理函数中的参数

        btnHandler: function(event){
        console.log(event.target.dataset.info)
        }
        

        wxs脚本

        wxs(WeiXin Script)是小程序的一套脚本语言,结合WXML,可以构建出页面的结构

        1.没有兼容性:wxs不依赖于运行时的基础库版本,可以在所有版本的小程序中运行

        2与 javascript 不同:wxs与javascript是不同的语言,有自己的语法,并不和javascript一致

        3.隔离性:wxs的运行环境和其他javascript代码是隔离的,wxs中不能调用其他javascript文件中定义的函数,也不能调用小程序提供的API

        4.不能作为事件回调:wxs 函数不能作为组件的事件回调

        5.iOS设备上比 javascript 运行快:由于运行环境的差异,在iOS设备上小程序内的wxs会比javascript代码快2~ 20 倍。在android设备上二者运行效率无差异

        6.wxml 文件中的每个 <wxs></wxs> 标签,必须提供一个 module 属性,用来指定当前 <wxs></wxs> 标签的模块名。在单个wxml文件内,建议其值唯一

        wxs 遵循 CommonJS模块化规范

        在wxs中,可以使用CommonJS中规定的如下成员:

        1.module 对象:每个wxs都是独立的模块,每个模块均有一个内置的module对象,每个模块都有自己独立的作用域。

        2.module.exports:由于 wxs拥有独立作用域,所以在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见,通过module.exports 属性,可以对外共享本模块的私有变量与函数。

        3.require函数:在.wxs模块中引用其他 wxs 文件模块,可以使用require函数。

        wx:if

        在小程序中,使用 wx:if="{{condition}}" 来判断是否需要渲染该代码块

        <view wx:if="{{length > 5}}"> 1 </view>
        <view wx:elif="{{length > 2}}"> 2 </view>
        <view wx:else> 3 </view>
        

        block wx:if --block wx:for用法和这个类似

        因为 wx:if是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 <block></block> 标签将多个组件包装起来,并在上边使用wx:if控制属性

        <block wx:if="{{true}}">
          <view> view1 </view>
          <view> view2 </view>
        </block>
        

        注意:<block/>并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性

        hidden

        在小程序中,直接使用 hidden="{{condition}}" 也能控制元素的显示与隐藏

        <view hidden="{{condition}}"> 条件为 true 隐藏,条件为 false 显示 </view>
        

        wx:for

        在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。

        默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。

        使用 wx:for-item 可以指定数组当前元素的变量名

        使用 wx:for-index 可以指定数组当前下标的变量名

        <view wx:for="{{array}}"  wx:key="index" wx:for-index="idx" wx:for-item="itemName">
           索引是:{{idx}} 当前项是:{{itemName}}
        </view>
        

        key 值的注意点

        ①key 值必须具有唯一性,且不能动态改变

        ②key 的值必须是数字或字符串

        ③保留关键字 *this 代表在 for 循环中的 item 本身,它也可以充当 key 值,但是有以下限制:需要 item 本身是一个唯一的字符串或者数字。

        ④如不提供 wx:key,会报一个warning,如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。

        下拉刷新

        下拉刷新是移动端更新列表数据的交互行为,用户通过手指在屏幕上自上而下的滑动,可以触发页面的下拉刷新,更新列表数据

        启用下拉刷新两种方式:

        ①需要在 app.json 的window 选项中或页面配置中开启enablePullDownRefresh。但是,一般情况下,推荐在页面配置中为需要的页面单独开启下拉刷新行为。

        ②可以通过 wx.startPullDownRefresh() 触发下拉刷新,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。当处理完下拉刷新后,下拉刷新的 loading效果会一直显示,不会主动消失,所以需要手动隐藏下拉刷新的loading效果。此时,调用 wx.stopPullDownRefresh() 可以停止当前页面的下拉刷新。

        下拉刷新窗口的样式配置

        需要在 app.json 的 window 选项中或页面配置中修改backgroundColor 和 backgroundTextStyle 选项。

        lbackgroundColor用来配置下拉刷新窗口的背景颜色,仅支持16进制颜色值

        lbackgroundTextStyle用来配置下拉刷新 loading 的样式,仅支持 dark 和 light

        上拉加载更多

        在移动端,随着手指不断向上滑动,当内容将要到达屏幕底部的时候,页面会随之不断的加载后续内容,直到没有新内容为止,我们称之为上拉加载更多。上拉加载更多的本质就是数据的分页加载

        onPageScroll(obj) 监听用户滑动页面事件

        属性类型说明
        scrollTopNumber页面在垂直方向已滚动的距离,单位px

        onShareAppMessage(obj)

        监听用户点击页面内转发按钮(组件open-type=“share”)或右上角菜单“转发”按钮的行为,并自定义转发内容。其中Object参数说明如下:

        参数类型说明
        fromString转发事件来源;button:页面内转发按钮;menu:右上角转发菜单
        targetObject如果 from 值是 button,则 target 是触发这次转发事件的 button,否则为 undefined
        webViewUrlString页面中包含<web-view>组件时,返回当前<web-view>的url

        同时,此转发事件需要 return 一个 Object,用于自定义转发内容,返回内容如下

        参数说明默认值
        title转发标题当前小程序的名称
        path转发路径当前页面path,必须是以/开头的完整路径
        imageUrl自定义图片路径,支持PNG和JPG使用默认截图

        onTabItemTap(Object)

        点击 tab 时触发,其中 Object参数说明如下:

        参数类型说明
        indexString被点击tabItem的序号,从0开始
        pagePathString被点击tabItem的页面路径
        textString被点击tabItem的按钮文字

        3.页面导航、网络数据请求、组件

        页面导航

        页面导航就是页面之间的跳转,小程序中页面之间的导航有两种方式:

        ① 声明式导航:通过点击navigator 组件实现页面跳转的方式;

        ② 编程式导航:通过调用小程序的API接口实现跳转的方式;

        声明式导航

        1.导航到非 tabBar 页面:非 tabBar页面指的是没有被当作 tabBar进行切换的页面。

        <navigator url='/pages/info/info'>去info页面</navigator>
        

        上述代码使用 url 属性指定要跳转到的页面路径;其中,页面路径应该以 / 开头,且路径必须提前在app.json的 pages节点下声明,才能实现正常的跳转。

        2.导航到 tabBar 页面:如果 navigator 组件单纯使用 url 属性,无法导航到 tabBar 页面,需要结合 open-type 属性进行导航

        <navigator url='/pages/home/home' open-type='switchTab'>
            导航到home页面
        </navigator>
        

        3.后退导航:需要把 open-type 设置为 navigateBack,同时使用 delta属性指定后退的层数

        <navigator open-type='navigateBack' delta='1'>
            返回上一页
        </navigator>
        

        编程式导航

        1.导航到非 tabBar 页面:通过 wx.navigateTo(Object object) 方法,可以跳转到应用内的某个页面。但是不能跳到 tabbar页面

        属性类型是否必填说明
        urlString需要跳转的应用内非 tabBar 的页面的路径, 路径后可以带参数。参数与路径之间使用 ?分隔,参数键与参数值用 = 相连,不同参数用 & 分隔;如 ‘path?key=value&key2=value2’
        successfunction接口调用成功的回调函数
        failfunction接口调用失败的回调函数
        completefunction接口调用结束的回调函数(调用成功、失败都会执行)

        2.导航到 tabBar 页面:通过 wx.switchTab(Object object) 方法,可以跳转到 tabBar页面,并关闭其他所有非 tabBar页面

        属性类型是否必填说明
        urlString需要跳转的 tabBar 页面的路径(需在app.json的tabBar字段定义的页面),路径后不能带参数
        successfunction接口调用成功的回调函数
        failfunction接口调用失败的回调函数
        completefunction接口调用结束的回调函数(调用成功、失败都会执行)

        3.后退导航:通过 wx.navigateBack(Object object) 方法,关闭当前页面,返回上一页面或多级页面

        属性类型是否必填说明
        deltanumber返回的页面数,如果delta大于现有页面,则返回到首页
        successfunction接口调用成功的回调函数
        failfunction接口调用失败的回调函数
        completefunction接口调用结束的回调函数(调用成功、失败都会执行)

        导航传参

        1.声明式导航传参:navigator 组件的 url属性用来指定导航到的页面路径,同时路径后面还可以携带参数,参数与路径之间使用 ?分隔,参数键与参数值用 = 相连,不同参数用 & 分隔。

        <navigator url='/pages/logs/logs?name=zs&age=20'>去logs页面</navigator>
        

        2.编程式导航传参:wx.navigateTo(Object object) 方法的 object 参数中,url 属性用来指定需要跳转的应用内非 tabBar 的页面的路径, 路径后可以带参数。参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 & 分隔

        wx.navigateTo({
          url: '/pages/logs/logs?name=zs&age=20',
        })
        

        3.接收传参:最终导航到的页面可以在 onLoad 生命周期函数中接收传递过来的参数

        //生命周期函数--监听页面加载
        onLoad: function(options) {
           console.log(options) // options 就是导航传递过来的参数
        }
        

        4.自定义编译模式快速传参

        小程序每次修改代码并编译后,会默认从首页进入,但是在开发阶段,我们经常会针对特定的页面进行开发,为了方便编译后直接进入对应的页面,可以配置自定义编译模式,步骤如下:

        ①单击工具栏上的“普通编译”下拉菜单;

        ②单击下拉菜单中的“添加编译模式”选项;

        ③在弹出的“自定义编译条件窗口”,按需添加模式名称、启用页面、启动参数、进入场景等。

        网络数据请求

        配置服务器域名

        每个微信小程序需要事先设置一个通讯域名,小程序只可以跟指定的域名进行网络通信。

        服务器域名请在 「小程序后台-开发-开发设置-服务器域名」中进行配置,配置时需要注意:

        1.域名只支持 https(request、uploadFile、downloadFile)和wss(connectSocket) 协议

        2.域名不能使用 IP地址或localhost

        3.域名必须经过 ICP备案

        4.服务器域名一个月内可申请5次修改

        发起 get请求

        调用 wx.request(Object object) 方法发起 get请求

        wx.request({// 请求的URL地址,必须基于 HTTPS 协议
        url: 'https://www.liulongbin.top:8082/api/get',
        // 发送到服务器的数据
        data: { name: 'zs', age: 20 },
        // 成功之后的回调函数
        success: function(result) {
        	console.log(result)
        }
        })
        

        发起post请求

        调用 wx.request(Object object) 方法发起 post请求

        wx.request({
        url: 'https://www.liulongbin.top:8082/api/post',
        method: 'POST', // 设置请求类型,如果不设置,默认发起 GET 请求
        data: { name: 'ls', gender: '男' }, // 发送到服务器的数据
        success: function(result) {
        	console.log(result)
        }
        })
        

        引用组件

        ①在需要引用组件的页面中,找到页面的.json 配置文件,新增 usingComponents节点

        ②在 usingComponents中,通过键值对的形式,注册组件;键为注册的组件名称,值为组件的相对引用路径

        ③在页面的 .wxml 文件中,把注册的组件名称,以标签形式在页面上使用,即可把组件展示到页面上

        使用样式美化组件

        组件对应 wxss 文件的样式,只对组件 wxml内的节点生效。编写组件样式时,需要注意以下几点:

        ①组件和引用组件的页面不能使用id选择器(#a)、属性选择器([a])和标签名选择器,请改用class选择器。

        ②组件和引用组件的页面中使用后代选择器(.a .b)在一些极端情况下会有非预期的表现,如遇,请避免使用。

        ③子元素选择器(.a>.b)只能用于 view 组件与其子节点之间,用于其他组件可能导致非预期的情况。

        ④继承样式,如 font 、 color ,会从组件外继承到组件内。

        ⑤除继承样式外, app.wxss 中的样式、组件所在页面的样式对自定义组件无效。

        为组件传递properties的值

        <!-- 引用组件的页面模板 -->
        <view>
          <component-tag-name prop-a="{{dataFieldA}}" prop-b="{{dataFieldB}}">
          </component-tag-name>
        </view>
        

        组件的属性 propA 和 propB 将收到页面传递的数据。页面可以通过 setData来改变绑定的数据字段

        注意:在定义 properties时,属性名采用驼峰写法(propertyName);在 wxml 中,指定属性值时,则对应使用连字符写法(property-name=“alue”),应用于数据绑定时,采用驼峰写法(attr="{{propertyName}}"

        数据监听

        数据监听器可以用于监听和响应任何属性和数据字段的变化,从而执行特定的操作。作用类似于vue 中的 watch。数据监听器从小程序基础库版本2.6.1 开始支持。

        Component({
          observers: {
            '字段A, 字段B': function(字段A的新值,字段B的新值) {
              // do something
            }
          }
        })
        

        监听子数据字段的变化

        Component({
          observers: {
            'some.subfield': function (subfield) {
              // 使用 setData 设置 this.data.some.subfield 时触发
              // (除此以外,使用 setData 设置 this.data.some 也会触发)
            },
            'arr[12]': function (arr12) {
              // 使用 setData 设置 this.data.arr[12] 时触发
              // (除此以外,使用 setData 设置 this.data.arr 也会触发)
            }
          }
        })
        

        组件的主要生命周期

        1.组件实例刚刚被创建好时, created生命周期被触发。此时还不能调用 setData 。通常情况下,这个生命周期只应该用于给组件 this 添加一些自定义属性字段。

        2.在组件完全初始化完毕、进入页面节点树后, attached生命周期被触发。此时, this.data 已被初始化完毕。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。

        3.在组件离开页面节点树后, detached生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则detached 会被触发。

        Component({
          lifetimes: {
            attached() {}, // 在组件实例进入页面节点树时执行
            detached() {}, // 在组件实例被从页面节点树移除时执行
          },
          // 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
          attached() {}, // 在组件实例进入页面节点树时执行
          detached() {}, // 在组件实例被从页面节点树移除时执行
          // ...
        })
        

        组件所在的页面的生命周期

        Component({
          pageLifetimes: {
            show() { // 页面被展示
            },
            hide() { // 页面被隐藏
            },
            resize(size) { // 页面尺寸变化
            }
          }
        })
        

        4.插槽、WePY框架

        默认插槽

        <!-- 组件模板 -->
        <view class="wrapper">
          <view>这里是组件的内部节点</view>
          <slot></slot>
        </view>
        
        <!-- 引用组件的页面模板 -->
        <view>
          <component-tag-name>
            <!-- 这部分内容将被放置在组件 <slot> 的位置上 -->
            <view>这里是插入到组件slot中的内容</view>
          </component-tag-name>
        </view>
        

        启用多个插槽

        Component({
          options: {
            multipleSlots: true // 在组件定义时的选项中启用多slot支持
          },
          properties: { /* ... */ },
          methods: { /* ... */ }
        })
        

        可以在组件的 wxml 中使用多个 slot 标签,以不同的 name 来区分不同的插槽,使用时,用 slot 属性来将节点插入到不同的 slot 中

        <!-- 引用组件的页面模板 -->
        <view>
          <component-tag-name>
            <!-- 这部分内容将被放置在组件 <slot name="before"> 的位置上 -->
            <view slot="before">这里是插入到组件slot name="before"中的内容</view>
            <!-- 这部分内容将被放置在组件 <slot name="after"> 的位置上 -->
            <view slot="after">这里是插入到组件slot name="after"中的内容</view>
          </component-tag-name>
        </view>
        

        组件之间的基本通信方式

        ①WXML 数据绑定:用于父组件向子组件的指定属性传递数据,仅能设置 JSON 兼容数据(自基础库版本 2.0.9 开始,还可以在数据中包含函数)。

        ②事件:用于子组件向父组件传递数据,可以传递任意数据。

        如果以上两种方式不足以满足需要,父组件还可以通过 this.selectComponent 方法获取子组件实例对象,这样就可以直接访问组件的任意数据和方法

        通过事件监听实现子向父传值

        ①在父组件的 js 中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件

        ②在父组件的 wxml 中,通过自定义事件的形式,将步骤一中定义的函数引用,传递给子组件

        ③在子组件的 js 中,通过调用 this.triggerEvent(‘自定义事件名称’, { /* 参数对象 */ }) ,将数据发送到父组件

        ④在父组件的 js 中,通过 e.detail 获取到子组件传递过来的数据

        WePY框架

        WePY 是腾讯官方出品的一个小程序快速开发框架,对原生小程序的开发模式进行了再次封装,更贴近于MVVM 架构模式,并支持ES6/7的一些新特性,同时语法风格更接近于Vue.js,使用 WePY 框架能够提高小程序的开发效率。

        注意:WePY 只是小程序的快速开发框架之一,市面上还有如 mpvue 之类的小程序开发框架也比较流行

        安装WePY框架

        npm install wepy-cli -g
        

        初始化WePY项目

        wepy init standard myproject
        

        其中,”wepy init” 是固定写法,代表要初始化 wepy 项目;”standard” 代表模板类型为标准模板,可以运行”wepy list” 命令查看所有可用的项目模板; ”myproject” 为自定义的项目名称。

        注意:创建项目的时候,要勾选 ESLint 选项!

        使用 wepy init 命令初始化项目后,只是得到了一个模板项目,如果想开启实时编译,得到小程序项目,步骤如下:

        ①运行 cd myproject 切换至 WePY 项目根目录

        ②运行 npm install 安装 WePY 项目依赖项

        ③运行 wepy build --watch 开启实时编译

        注意:wepy build --watch 命令,会循环监听 WePY 项目中源代码的变化,自动编译生成小程序项目,生成的小程序项目默认被存放于dist 目录中。

        创建 .wpy 页面注意事项

        ①每个页面的 script 标签中,必须导入 wepy 模块,并创建继承自 wepy.page 的页面类;否则会报错。

        ②每个页面的路径,必须记录到 app.wpy 的 config ->pages 数组中。

        页面路径记录完毕之后,必须再回到页面文件中,摁下 Ctrl + S 快捷键重新编译生成页面,否则会报错

        事件传参优化写法

        如果 @ 符号绑定的事件处理函数需要传参,可以采用优化的写法,示例如下:

        bindtap="clickHandler"data-index={{index}} 替换为@tap="click({{index}})"

        使用wxs脚本

        ①将 wxs 脚本定义为外联文件,并且后缀名为.wxs

        ②在 <script></script>标签内,通过 import 导入相对路径的 wxs 模块

        import testWXS from '../wxs/test.wxs'
        

        ③在当前页面的 class 类中,通过 wxs = { } 注册刚才导入的 wxs 模块

        wxs = {
            test: testWXS
          }
        

        注意:被注册的 wxs 模块,只能在当前页面的 template 中使用,不能在script中使用

        配置 promisify 启用 async 和 await

        需要手动开启,在src -> app.wpy ,找到constructor() 构造函数,添加this.use('promisify')

        constructor() {
          super()
          this.use('requestfix')
          this.use('promisify') // 添加此行代码,即可启用 async 和 await
        }
        

        使用 WePY 发起get请求

        //通过 wepy.request() 发起get请求
        methods = {
          async getInfo() {
            const res = await wepy.request('https://www.liulongbin.top:8082/api/get')
            console.log(res)
          }
        }
        

        使用 WePY 发起post请求

        methods = {
          async postInfo() {
            const res = await wepy.request({
              url: 'https://www.liulongbin.top:8082/api/post',
              method: 'post',
              data: { name: 'zs', age: 20 }
            })
            console.log(res)
          }
        }
        

        异步更新数据

        在异步函数中更新数据的时候,页面检测不到数据的变化,必须手动调用 this.$apply 方法, 强制页面重新渲染

        methods = {
          async getInfo() { // 被 async 修饰的函数叫做异步函数
            const res = await wepy.request('https://www.liulongbin.top:8081/api/get)
            this.getMsg = res.data
            //需要重新渲染页面数据才能更新
            this.$apply()
          }
        }
        
      • 18
        点赞
      • 106
        收藏
        觉得还不错? 一键收藏
      • 1
        评论
      评论 1
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

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

      抵扣说明:

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

      余额充值