添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

html5新特性

1.语义标签

常用的语义化标签:
<header></header>头部
<nav></nav>导航栏
<section></section>区块(有语义化的div)
<main></main>主要区域
<artical></artical>主要内容
<aside></aside>侧边栏
<footer></footer>底部   ...
这些标签可以在页面中使用多次

Video(视频)
Audio(音频)
使用它们可以很方便的在页面中嵌入音频和视频,不用在去使用flash和其他浏览器插件

2.增强型表单/表单2.0

1.新的input type

2.新的表单元素

<input><textarea><select><option>....

<datalist>:数据列表,为input提供输入建议列表

<progress>:进度条,展示连接/下载进度

<meter>:刻度尺/度量衡,描述数据所处的阶段,红色(危险)=>黄色(警告)=>绿色(优秀)

<output>:输出内容,语义上表示此处的数据是经过计算而输出得到的
type=‘email’‘tel’文本等限制
tel:电话控件
url:url地址控件
email:email控件,有校验功能
color:颜色控件
date:日期控件(年,月,日,不包含时间),火狐支持,谷歌支持time:时间控件,火狐支持,谷歌支持datetime-local:日期时间控件,暂时火狐不支持,谷歌支持month: 月插件等。。

3.表单元素的新属性

 通用属性:

placeholder:占位提示文字

mutiple:是否允许多个输

autofocus:自动获得输入焦点

form:指定输入元素所从属的表单,可以实现输入框放在表单外部并能被提交的效果

验证属性(了解即可):

required:输入框内容不能为空

min:允许输入的数字最小值

max:允许输入的数字最大值

minlength:允许输入的字符串最小长度

maxlength:允许输入的字符串最大长度

pattern:输入框内容必须符合的正则表达式

required:规定是否为必填项

3.视频和音频

 视频播放:<video src=""><video>

查看视频的所有属性、方法、事件:console.log(videoBirds);

音频播放:<audio src=""></audio>

查看视频的所有属性、方法、事件:console.log(bgMusic);
WEB中可用的绘图技术:

(1)Canvas绘图:H5原生技术,基于网页画布绘制2D位图绘图技术,善于表现细腻颜色

(2)SVG绘图:H5借鉴技术,基于SVG绘图空间绘制2D矢量图绘图技术,缩放不会失真

(3)WebGL绘图:尚不是H5标准技术,基于HTML5 Canvas提供硬件3D加速渲染;有一个非常强大3D扩展库:three.js

4.Canvas绘图

 H5原生技术,基于网页画布2D位图绘图技术,善于表现细腻颜色,可用于统计图表、页面游戏、地图应用、网页特效等。

使用Canvas的步骤:

<canvas id="c2" width="400" height="300"></canvas>

Canvas自身是一个300*150的inline-block元素;注意:Canvas画布尺寸不能使用CSS设置——会对整个图像进行扭曲!

使用H5 Canvas API进行绘图:

var ctx = c2.getContext('2d');

//绘制矩形

ctx.fillStyle = '#000' 填充颜色/渐变色对象

ctx.strokeStyle = '#000' 描边颜色/渐变色对象

ctx.lineWidth = 1 描边线宽度

ctx.fillRect(x, y, w, h): 填充矩形

ctx.strokeRect(x, y, w, h): 描边矩形

ctx.clearRect(x, y, w, h): 描边矩形

//绘制文本

ctx.font = '10px sans-serif'

ctx.textBaseline = 'alphabetic/top/bottom'

ctx.fillStyle = '#000'

ctx.strokeStyle = '#000'

ctx.fillText(txt, x, y) 填充文本

ctx.strokeText(txt, x, y) 描边文本

ctx.measureText(txt).width 测量文本基于当前字体设置的宽度

//绘制路径——概念上类似于PS中的钢笔工具

ctx.beginPath()

ctx.moveTo()

ctx.lineTo()

ctx.arc()

ctx.rect()

ctx.ellipse()

ctx.closePath()

-----------------------------

ctx.stroke() 基于现有路径进行描边

ctx.fill() 基于现有路径进行填充

ctx.clip() 基于现有路径进行裁切

//绘制图像

ctx.drawImage(img, x, y) 绘制图像(原始尺寸)

ctx.drawImage(img, x, y, w, h) 绘制图像(指定尺寸)

//绘图上下文变形和状态保持

ctx.rotate() 图像旋转

ctx.translate() 图像平移

ctx.scale() 图像缩放

------------------

ctx.save() 绘图上下文的保存

ctx.restore() 绘图上下文的恢复

2.Chart.js —— 了解

简单且灵活的JS图表绘制工具库,基于Canvas实现。类似于的工具还有ECharts、FreeChart、FusionCharts.....

官网:http://www.chartjs.org/

基本使用方法:

<canvas id="c3"></canvas>

<script src="js/Chart.js"></script>

<script>

new Chart(c13, {

type: 'bar/line/pie',

data: {

labels: ['','','',''],

datasets: [{

label: '',

data: [...]

} ]

}

});

</script>

5.SVG绘图

  Scalable Vector Graphic,可缩放向量图

在H5标准之前的使用方法:SVG标签不能直接书写在网页中,只能编写在独立的XML文档中;

网页中使用<img src="x.svg">进行嵌入

纳入H5标准后的使用方法:SVG标签可以直接书写在网页中。

Canvas与SVG的不同:

(1)Canvas是位图;SVG是矢量图

(2)Canvas是JS绘图技术(不是DOM元素);SVG是标签绘图技术(是DOM元素)

(3)Canvas内容不能使用CSS;SVG内容可以使用CSS;

(4) Canvas内容不方便绑定事件处理;SVG内容方便进行事件绑定

常用的SVG图形:

(1)矩形

<rect width="100" height="50" x="400" y="350" fill="#f0f" fill-opacity="0.3" stroke="#00f" stroke-width="6" stroke-opacity=".3"></rect>

(2)圆形

<circle r="100" cx="400" cy="300" fill="#f0f" fill-opacity="0.4" stroke="#00f" stroke-width="6" stroke-opacity=".4"></circle>

(3)椭圆

<ellipse rx="100" ry="50" cx="400" cy="350" fill="#f0f" fill-opacity=".4" stroke="#00f" stroke-width="6" stroke-opacity=".4"></ellipse>

(4)直线(没有fill只有stroke)

<line x1="45" y1="350" x2="450" y2="350" stroke="#f00" stroke-width="4px" stroke-opacity=".4"></line>

(5)折线(fill必须设置透明/stroke必须手工指定)

<polyline points="150,200 250,100 350,300 450,50" stroke="#00f" stroke-width="6" stroke-opacity=".4" fill="transparent"></polyline>

(6)多边形

<polygon points="100,150 100,300 400,300 400,150 250,220" fill="#f0f" fill-opacity=".4" stroke="#00f" stroke-width="6" stroke-opacity=".4"></polygon>

(7)文本

<text alignment-baseline="before-edge" font-size="40" fill="#f0f" stroke="#00f">达内科技2018ajgy</text>

(8)图像

<image xlink:href="img/p3.png" x="400" y="200" width="100" height="200"></image>

扩展小知识:

(1)使用滤镜(高斯模糊)

参考MDN手册:https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/filter

声明滤镜:

<filter id="f2">

<feGaussianBlur stdDeviation="3"></feGaussianBlur>

</filter>

使用滤镜:

<image/text/rect filter="url(#f2)">

(2)使用颜色渐变对象

声明渐变对象:

<linearGradient id="g2" x1="0" y1="0" x2="100%" y2="0">

<stop offset="0" stop-color="red"></stop>

<stop offset="0.5" stop-color="yellow"></stop>

<stop offset="1" stop-color="green"></stop>

</linearGradient>

使用渐变对象:

<text/rect fill="url(#g2)" stroke="url(#g2)">

6.地理定位

  通过浏览器获取当前用户的所在地理坐标,以实现“LBS服务”(Location Based Service),如实时导航、周边推荐。

情形1:用户使用手机浏览器——可以根据内置GPS芯片读取数据

情形2:用户使用PC浏览器——可以根据电脑的IP地址进行反向查询(需要很大的IP分配库)

window.navigator.geolocation : {

watchPosition(){},

clearWatch(){},

getCurrentPosition(function(pos){

'定位成功'

定位时间:pos.timestamp

维度:pos.coords.latitude

经度:pos.coords.longitude

海拔:pos.coords.altitude

速度:pos.coods.speed

}, function(err){

'定位失败'

}){},

}

7.拖放API

 H5之前没有拖放API,可以使用“鼠标按下 + 鼠标移动”两个事件来模拟用户拖动事件。

H5之后专门提供了七个鼠标拖动相关事件句柄:

拖动的源对象(source)可能触发的事件:

dragstart:拖动开始

drag:拖动中

dragend:拖动结束

拖动的目标对象(target)可能触发的事件:

dragenter:拖动进入

dragover:拖动悬停

drop:松手释放

dragleave:拖动离开

注意:拖放API事件句柄中所有的事件对象都有一个dataTransfer属性(数据运输对象),用于在源对象和目标对象间传递数据。

源对象:event.dataTransfer.setData(key, value)

目标对象:var value = event.dataTransfer.getData(key)

8.WebWorker

 背景:Chrome浏览器中发起资源请求的有6个线程;但是只有1个线程负责渲染页面——称为UI主线程——浏览器中所有的代码只能由一个线程来执行。

问题:若浏览器加载了一个很耗时的JS文件(可能影响DOM树结构),浏览器必须等待该文件执行完成才会继续执行后续的代码(HTML/CSS/JS等)——如果一个JS文件要执行10s(可能有很深的循环/递归等科学计算/解密),会发生什么?——执行耗时JS任务过程中,会暂停页面中一切内容的渲染以及事件的处理。

解决方案:H5新特性——Web Worker

Worker的本质:就是一个执行指定任务的独立线程;且该线程可以与UI主线程进行消息数据传递。使用方法:

HTML文件中:

var w = new Worker('js/x.js')

w.postMessage('发送给Worker线程的消息');

w.onmessage = function(e){

e.data; //来自Worker线程的消息

}

JS文件中:

onmessage = function(e){

var data = e.data; //接收UI线程的消息

//执行耗时任务....

postMessage(result); //给UI线程发送消息

}

注意:Worker任务不允许直接操作DOM树,也不允许使用任何的BOM对象!需要的数据只能由UI主线程来传递,处理的结果也必须交由UI线程来显示。

9.WebStorage

 Web项目存储数据常用的方案:

(1)服务器端存储

1)数据库存储,如商品、用户等核心数据

2)Session/内存存储,如用户的登录信息

(2)客户端存储

3)Cookie存储,如用户偏好、访问历史,浏览器兼容性好但处理麻烦且容量限制

4)H5 WebStorage存储,如用户偏好、访问历史等安全要求的数据,老IE不兼容但易使用且容量大

H5WebStorage存储具体涉及到两个对象:

(1)window.sessionStorage:类数组对象,通过key=>value对存储字符串数据——会话级存储

添加数据:sessionStorage['key'] = 'value'

修改数据:sessionStorage['key'] = 'newValue'

删除数据:delete sessionStorage['key']

获得数据:var v = sessionStorage['key']

(2)window.localStorage:类数组对象,通过key=>value对存储字符串数据——本地/跨会话级/永久存储

添加数据:localStorage['key'] = 'value'

修改数据:localStorage['key'] = 'newValue'

删除数据:delete localStorage['key']

获得数据:var v = localStorage['key']

10.WebSocket

css3新增

新增选择器 p:nth-child(n){color: rgba(255, 0, 0, 0.75)}

弹性盒模型 display: flex;

多列布局 column-count: 5;

媒体查询 @media (max-width: 480px) {.box: {column-count: 1;}}

个性化字体 @font-face{font-family:BorderWeb;src:url(BORDERW0.eot);}

颜色透明度 color: rgba(255, 0, 0, 0.75);

圆角 border-radius: 5px;

渐变 background:linear-gradient(red, green, blue);
background-image: radial-gradient(red 5%, yellow 15%, green 60%);

阴影 box-shadow:3px 3px 3px rgba(0, 64, 128, 0.3);

倒影 box-reflect: below 2px;

文字装饰 text-stroke-color: red;

文字溢出 text-overflow:ellipsis;

背景效果 background-size: 100px 100px;

边框效果 border-image:url(bt_blue.png) 0 10;

2d 转换
旋转 transform: rotate();

倾斜 transform: skew();

平移 transform:translate();

缩放 transform: scale();

平滑过渡 transition:;


<video src="1.mp4" autoplay 自动播放 loop 循环 controls 控件></video>
<audio src="" autoplay 自动播放 loop 循环 controls 控件></audio>

css3新特性

属性选择器,E[属性=‘属性值’]也就是   input[type=‘text’]
结构伪类选择器
伪元素选择器
2d转换
3d转换
动画
过度
字体图标
浏览器私有前缀

前端优化的途径有很多,按粒度大致可以分为两类,第一类是页面级别的优化,例如 HTTP请求数、脚本的无阻塞加载、内联脚本的位置优化等 ;第二类则是代码级别的优化,例如 Javascript中的DOM 操作优化、CSS选择符优化、图片优化以及 HTML结构优化等等

HTML5

<input type="">
type{
文本 text (设定最大输入数 maxlength 、 框内提示文字 placeholder)
密码 password (设定最大输入数 maxlength 、 框内提示文字 placeholder)
单选 radio (多个选项中单选name需相同 ,添加label标签后点击文本也可以选择)
<p><label for="man">男</label> <input type="radio" id="man" name="sex"></p>
<p><label for="woman">女</label><input type="radio" id="woman" name="sex"><br></p>
年月日 date
多选 checkbox (默认选中checkted)JS: checkbox.checked (选中值为true,未选中值为false)
数字选择 number (设定上下限 max min 设定选择间距step)
文件选择 file
图片 imgage
提交 submit
重置 reset
禁用 disabled = true //是否禁用
}
下拉框单选<select> <option>123</option> </select>
{
作为提示不可选中 disabled
默认选项 selected
}
自由文本 <textarea></textarea>
{
行 cols 列 rows
框内提示文字 placeholder
}
<table>
{
宽(width)
对齐方式 align (left center right)
表格边框宽度 (border)
单元边沿与其内容之间的空白 (cellpadding)
单元格之间的空白 (cellspacing)
合并单元格 (跨行合并:rowspan="合并单元格个的个数"
跨列合并:colspan="合并单元格个的个数" )
外侧边框的哪个部分是可见的(void、above、below、hsides...)
内侧边框的哪个部分是可见的(none、groups、rows、cols、all)
表格的摘要(summary)
}





内容自动换行:
word-wrap: normal/break-word;
normal 只在允许的断字点换行(浏览器保持默认处理,默认值)。
break-word 在长单词或 URL 地址内部进行换行。

word-break: normal/break-all/keep-all;
normal 使用浏览器默认的换行规则。(默认值)
break-all 允许在单词内换行。
keep-all 只能在半角空格或连字符处换行。
1.块级标签 块级元素 :独占一行 默认宽度100% 可以设置宽高
块级元素:<h1>-<h6>、p、div、ul、ol、li...
宽度默认100%;默认独占一行;可以直接设置 宽 高 边距 填充

2.行内标签 行内元素 :并排显示 默认宽度是内容宽度 不可以直接设置宽高
行内元素:a,strong,b,em,i,del,s,ins,u,span...
宽度自动;默认并排显示,不能直接设置 宽 高 边距 填充

3.行内块元素 :可以设置宽高 并排显示
行内块元素:img、input
宽度自动;默认并排显示,可以直接设置 宽 高 边距 填充,自带2-3像素的边距



三种转换:
元素->行内: style=" display:inline; "
元素->块: style=" display:block; "
元素->行内块: style=" display:inline-block; "

背景图(css 中)

background: slateblue;			设置背景色
background-image: url("./images/sgwe.jpg"); 设置背景图片
background-repeat: no-repeat; 设置图片不重复
background-position: ; 水平方向 垂直方向
background-position-x: ; 设置水平位置
background-position-y: ; 设置竖直位置
background-position: 10px 100px; 如下
background-position: x y; 没写哪个哪个就是默认全局居中
background-position: center top; 设置位置在头部的中间
background-attachment: fixed; 设置背景图片附着(固定)
background-size: cover; 平铺在整个容器中 auto 图片本身大小
border: 1px solid #000; 设置边框 粗细 实线/虚线(solid/dashed) 颜色
border-radius: 50%; 设置边框圆角 (单位 px或% 都行)
box-shadow:inset 5px 5px 5px green; 设置元素阴影 内阴影inset 不写就是外阴影 (三个值:横向位置 纵向位置 虚化)
Background-size:100% 100%; 背景图一个百分之百占比
transparent 透明色



background-image: url("./images/sgwe.jpg");
/* 设置背景图片 */
background-repeat: no-repeat;
/* 设置背景图片平铺 */
/* background-position:50 ; 水平方向 垂直方向 */
/* background-position: center top; */
/* 在头部的中间 */
/* background-position: 10px 100px; */
/* background-position: x y;没写哪个哪个就是默认全局居中 */
/* 设置背景图片位置 */
background-attachment: fixed;
/* 设置背景图片附着 */
/* background: slateblue url("./images/sgwe.jpg") no-repeat fixed 250px 0; */
background-size: cover;
/* 设置背景图片尺寸 需要单独写出来*/


object-fit CSS 属性指定可替换元素的内容应该如何适应到其使用的高度和宽度确定的框。
可以通过使用 object-position 属性来切换被替换元素的内容对象在元素框内的对齐方式。
contain:被替换的内容将被缩放,以在填充元素的内容框时保持其宽高比。 整个对象在填充盒子的同时保留其长宽比,因此如果宽高比与框的宽高比不匹配,该对象将被添加“黑边”。
cover:被替换的内容在保持其宽高比的同时填充元素的整个内容框。如果对象的宽高比与内容框不相匹配,该对象将被剪裁以适应内容框。
fill:被替换的内容正好填充元素的内容框。整个对象将完全填充此框。如果对象的宽高比与内容框不相匹配,那么该对象将被拉伸以适应内容框。
none:被替换的内容将保持其原有的尺寸。
scale-down:内容的尺寸与 none 或 contain 中的一个相同,取决于它们两个之间谁得到的对象尺寸会更小一些。

vertical-align: middle;
nav 标签为导航栏标签

导航栏内用ul il 写

复制付费文本

方法1:F12 F1 设置禁用JS

方法2:F12 元素 事件帧监听 删除复制事件

方法3:找到HTML中存放内容的段落,找到父级,添加一个id或者class,然后在控制台打印console.log(document.getElementById('自建ID').innerText)

1.类选择器
在此例中,所有带有 class="center" 的 HTML 元素将为红色且居中对齐:
例1 .center {
text-align: center;
color: red;
}
例2 <head>
<style>
p.center { (只影响p标签中有center类的元素)
text-align: center;
color: red;
}

p.large { (只影响p标签中有large类的元素)
font-size: 300%;
}
</style>
</head>
<body>
<h1 class="center">这个标题不受影响</h1>
<p class="center">本段将是红色并居中对齐。</p>
<p class="center large">本段将是红色、居中对齐,并使用大字体。</p>
</body>
2.标签选择器
页面上的所有 <p> 标签都将居中对齐,并带有红色文本颜色:
p {
text-align: center;
color: red;
}
3.id选择器(注意:id名称不能以数字开头)
这条 CSS 规则将应用于 id="para1" 的 HTML 元素:
#para1 {
text-align: center;
color: red;
}
4.通配符选择器
下面的 CSS 规则会影响页面上的每个 HTML 元素:
* {
text-align: center;
color: blue;
}
5.分组选择器
分组选择器选取所有具有相同样式定义的 HTML 元素
例3
<head>
<style>
.center,p { (所有元素中带有center类和p标签)
color: red;
}
</style>
</head>
<body>
<label class="center">本段将是红色</label>
<p>本段将是红色</p>
</body>
6.后代选择器(包含选择器)
用来选择元素或元素组的后代,写法就是把外层标签写在前面,内层标签写在后面,中间用空格分开。当标签发生嵌套的时候,内层标签就成为外层标签的后代;
<head>
<style>
.two p{
color:red;
}
</style>
</head>
<div class="two">
<p>aaaaaaa</p> (红)
<div>
<p>bbbbbbb</p> (红)
<div>
<p>fffffff</p> (红)
</div>
</div>
<p>bbbbbbb</p> (红)
<p>ccccccc</p> (红)
</div>
7.子元素选择器
只能选择作为某元素子元素的元素,其写法就是把父级标签写在前面,子集标签写在后面,中间跟一个>进行连接,注意,符号左右两侧各保留一个空格;
<head>
<style>
.two>div>p{
color: red;

}
</style>
</head>
<div class="two">
<p>aaaaaaa</p>
<div>
<p>bbbbbbb</p> (红色)
<div>
<p>fffffff</p>
</div>
</div>
<p>bbbbbbb</p>
<p>ccccccc</p>
</div>
8.:after 选择器
:after 选择器向选定元素的最后子元素后面插入内容,使用content 属性来指定要插入的内容
<style>
p:after
{
content:"- 注意我";
}
</style> /*在每个p标签后都会添加一个 - 注意我 */
</head>
<body>
<p>我的名字是 Donald</p>
<p>我住在 Ducksburg</p>
<p><b>注意:</b> :after在IE8中运行,必须声明 !DOCTYPE </p>
</body>
9.属性选择器
*[title] {color:red;} /*所有包含title属性的元素为红色*/
a[href] {color:red;} /*有herf属性的a标签颜色为红色*/
a[href][title] {color:red;} /*同时有herf 和 title属性的a 标签为红色*/
*[type|="wer"] {color: blue;} /*type属性值为wer的标签会被选择*/
{
color: red;
}


为 XML 文档使用属性选择器

a[href="#"] {color: red;} /*根据属性值选择*/
a[href="#"][title="W3School"] {color: red;} /*与上类似*/

p[class="i w"] /*类为i w 的P标签才会被选择*/
{
color: red;
}

p[class~="i"] /*类中有i 的 p 标签就会被选择*/
{
color: red;
}

伪类选择器

			伪元素为行内元素,可以转换为其他类型元素。
伪类选择器: 用于向某些选择器添加特殊的效果,比如给链接添加特殊效果,或选择第n个元素。
伪类选择器书写最大的特点是用冒号(:)表示

1.链接伪类选择器:
:link 选择所有未被访问的链接
:visited 选择所有已被访问的链接
:hover 选择鼠标指针位于其上的链接
:active 选择活动链接(鼠标按下未弹起的链接)

:hover 只能父级控制子级 ,若是兄弟级控制兄弟级, 写法: #a1:hover~#a2{}(注意hover后波浪线) 注意,hover效果 可以用写,可以用overflow:fidden写 不能用opacity:0 :hover 前不能有空格!!!

例1:
<head>
<style>
a:link{ (未被点击时为红色)
color:red;
}
a:visited{ (点击过后为黄色)
color:yellow;
}
a:hover{ (鼠标经过时为棕色)
color:brown;
}
a:active{ (鼠标被点击时为粉色)
color:pink;
}
</style>
</head>
<body>
<a href="#">好好学习</a>
</body>


2.focus伪类选择器用于选取获取焦点的表单元素,焦点就是光标 (仅用于<input type="text">文本框中,有聚焦作用)
例2:
<head>
<style>
input:focus{
(鼠标点击后输入框内为绿色)
}
input:hover{
(鼠标经过时背景颜色为红色)
</style>
</head>
<body>
<input type="text" style="outline: none;"> (outline:none; 外部边框为空)
</body>

3. .p::after{} .p::before{} 在元素后/前添加元素 元素内容为 content:"";

4.结构伪类选择器
p:first-child{} 匹配元素中的第一个元素(选择器选中的是父元素中的子元素)E:last-child 匹配元素中的最后一个元素


E:nth-child(n) 匹配元素中的第n个元素,这个n可以是数字也可以是公式也可以是关键字 公式:
2n :求偶数
2n+1:奇数
5n:5的倍数 5-10-15-20-25
n+5 :从第5个开始
-n+5:前5个
关键字:只有odd 和 even 两个关键字(奇数偶数)



优先级:!important	>	行内样式	>	内链样式	>	外部引入       ( !important 可直接添加在css样式中 )
后代选择器 > 子类选择器; 为同种选择器时,哪个的描述多哪个优先级高。
id 相当于身份证号; class 相当于小名。
.main {
height: calc(100% - 121px);
}
注意减号两边需要有空格!!!

样式 / 属性

引入css样式的三种类型:行内样式、内嵌样式(利用选择器)、外部引入。

外部引入的CSS:新建css文件,在html文件中<head>标签中添加<link rel="stylesheet" href="">标签。在 href="" 中添加css文件路径。
	color: aquamarine;
/* 字体颜色 */

/* 背景色 */
font-size: 20px; 因为该属性的值会被用于计算em和ex长度单位,定义该值可能改变其他元素的大小。
/* 字体大小 */
font-weight:
定义字体粗细:normal
正常粗细。与400等值。
bold
加粗。 与700等值。
lighter
比从父元素继承来的值更细(处在字体可行的粗细值范围内)。
bolder
比从父元素继承来的值更粗 (处在字体可行的粗细值范围内)。

②font-family:
定义字体
margin: 10px 20px 30px 40px;
/* 外边距 (顺时针为 上右下左) */
padding: 20px;
/* 内边距 */
font-family: "楷体";
/* 字体样式 */
font-style: italic;
/* 字体倾斜 */
font-weight: bold;
/* 字体粗细 */
text-align: center;
/* 字体对齐方式 */ 文字居中对齐
text-decoration: underline;
/* 字体下划线 */
text-indent: 2em;
/* 首行缩进 */
letter-spacing: 10px;
/* 设置字间距 */
line-height: 60px;
/* 设置行高 */
text-shadow: 30px 30px 30px blue;
/* 设置文本阴影:水平方向偏移量,垂直方向偏移量,阴影面积,阴影颜色 */
line-height: 50px ; ***其他元素使用频率也很高
/*设置行高*/
border-radius;
改边框厚度 改边框圆滑
background:transparent;
文本框透明
placeholder:
占位提示文字
margin: 100px auto;
/*强制文字在一行文本框内*/
word-wrap:break-word; //文字溢出换行

2.div

border: 10px solid black; 		
/* 虚线:dotted dashed */
/* 边框:宽度 实线 颜色 */
cursor:pointer //鼠标移上变手
target:				(不是css属性,直接写在a标签内)
_blank
_parent
_self
_top
framename
规定在何处打开链接

cursor:pointer //鼠标移上变手

a:link,定义正常链接的样式
a:visited,定义已访问过链接的样式
a:hover,定义鼠标悬浮在链接上时的样式
a:active,定义鼠标点击链接时的样式

注意:
在 CSS 定义中,a:hover 必须被置于 a:link 和 a:visited 之后,才是有效的。
在 CSS 定义中,a:active 必须被置于 a:hover 之后,才是有效的。


text-decoration​ 属性是用来设置 a 标签的划线属性的。其属性值有:
none:去掉下划线
underline:设置下划线
overline:在文本上方设置线条
line-through:在文本中间设置线条
initial:默认值
inherit:从父元素中继承

4.列表样式

list-style-type 属性的常见属性值的描述:

none:不使用项目符号
disc:实心圆
circle:空心圆
square:实心方块
decimal:阿拉伯数字
lower-alpha:小写英文字母
upper-alpha:大写英文字母
lower-roman:小写罗马数字
upper-roman:大写罗马数字
;            
/*隐藏该区域*/
opacity: 0; (调整透明度)
/*隐藏该区域(值为0.透明度为0;值为1,透明度为100%)*/

/*调整颜色透明度 (r,g,b,a) a值为透明度 */

z-index:;
调整元素显示优先级,必须配合定位使用

box-sizing: border-box;
盒子大小等于你设置的大小
border-radius: 5px; / 5%;
设置边框圆角
background:linear-gradient(red, green, blue);
background-image: radial-gradient(red 5%, yellow 15%, green 60%);
背景渐变
Background-size:100% 100%;
背景图一个百分之百占比

<link rel="icon" href="./img/火影logo.png"> 给标签前添加logo

盒子突起效果:
box-shadow:inset 0px 0px 10px black;
立体效果:
box-shadow:5px 5px 30px 10px black;

cursor:pointer //鼠标移上变手

position: absolute;
top:50%;
left:50%;
transform: translate(-50%,-50%);
/*将页面移到中央*/

button disabled = true 按钮不可按 按钮属性,不是css
transparent 透明色
list-style:none; 去除无序列表的符号



隐藏:
visibility: hidden

opacity:0




阻止鼠标事件:pointer-events是一个指针属性,是用于控制在什么条件下特定的图形元素可以成为指针事件的目标
值:none:该元素永远不会成为鼠标事件的 target
auto:默认值,表示指针事件已启用
...







object-fit CSS 属性指定可替换元素的内容应该如何适应到其使用的高度和宽度确定的框。
可以通过使用 object-position 属性来切换被替换元素的内容对象在元素框内的对齐方式。
contain:被替换的内容将被缩放,以在填充元素的内容框时保持其宽高比。 整个对象在填充盒子的同时保留其长宽比,因此如果宽高比与框的宽高比不匹配,该对象将被添加“黑边”。
cover:被替换的内容在保持其宽高比的同时填充元素的整个内容框。如果对象的宽高比与内容框不相匹配,该对象将被剪裁以适应内容框。
fill:被替换的内容正好填充元素的内容框。整个对象将完全填充此框。如果对象的宽高比与内容框不相匹配,那么该对象将被拉伸以适应内容框。
none:被替换的内容将保持其原有的尺寸。
scale-down:内容的尺寸与 none 或 contain 中的一个相同,取决于它们两个之间谁得到的对象尺寸会更小一些。
 1.整体居中				(建议使用)
.d2{
width: 300px;
height: 300px;
position: absolute;
top: 50%;
left: 50%;

transform: translate(-50%,-50%);
}
2.整体居中显示 (不建议使用)
.d2{
width: 200px;
height: 200px;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
3.设置行内居中:
(1).设置行高lint-height:;为父容器高度,行内自动垂直居中
(2).padding、margin
(3).定位
(4).position: absolute; top:0; bottom:0;
4.flex布局


5.vertical-align 属性设置元素的垂直对齐方式

baseline 默认。元素放置在父元素的基线上。
sub 垂直对齐文本的下标。
super 垂直对齐文本的上标
top 把元素的顶端与行中最高元素的顶端对齐
text-top 把元素的顶端与父元素字体的顶端对齐
middle 把此元素放置在父元素的中部。
bottom 把元素的顶端与行中最低的元素的顶端对齐。
text-bottom 把元素的底端与父元素字体的底端对齐。
% 使用 "line-height" 属性的百分比值来排列此元素。允许使用负值。
inherit 规定应该从父元素继承 vertical-align 属性的值。
设置盒模型的margin等属性时
值若唯一x,则上下左右均为x;
值若为二x,y,则上下为x,左右为y;
值若为三,x,y,z, 则上为x,左右为y,下为z;

注意:在已设置宽高的盒模型中添加内外边距后,盒模型会变大,但是可用空间还是原来的宽高;
在已添加内外边距盒模型的css中添加box-sizing: border-box;时将强制把盒模型的大小变回原本设置的宽高,盒模型中可用空间将被缩小;


解决内边距影响盒子大小的方法
box-sizing :(不包含margin)
content-box 是默认值。如果你设置一个元素的宽为100px,那么这个元素的内容区会有100px 宽,并且任何边框和内边距的宽度都会被增加到最后绘制出来的元素宽度中。
border-box 告诉浏览器:你想要设置的边框和内边距的值是包含在width内的。也就是说,如果你将一个元素的width设为100px,那么这100px会包含它的border和padding,内容区的实际宽度是width减去(border + padding)的值。大多数情况下,这使得我们更容易地设定一个元素的宽高。

iconfont

三种方法 (以字体的方式调整)
1.<head>中用<link>导入css文件 ; 将代码复制在标签中(<i >&#xe60f;</i> ,可以再对i标签进行修饰)
2.
可以让块级元素并排显示,浮动不会影响前面的元素 float:left;
高度坍塌:(父元素高度为0)
正常文档流的父元素,里面的所有子元素都为浮动元素的时候,父元素的高度不会被子元素所撑开
清除浮动:
1.父元素设置死高 /* 不建议使用 */
2.父元素设置溢出隐藏(没有溢出元素) 内容增多的时候容易造成不会自动换行导致内容被隐藏掉,无法显示要溢出的元素
/* 不建议使用 */
3.在父元素的结束标签前面添加一个空的块级元素,设置clear: both;属性,本质就是闭合浮动, 就是让父盒子闭合出口和 入口,不让子盒子出来
4. cf::after{
display:block;
clear: both;
content:"";
} 💖 /* 清除浮动 */
clear 属性:
left; 在左侧不允许浮动元素。
right; 在右侧不允许浮动元素。
both; 左右两侧都不允许浮动。
none; 默认值。允许浮动出现在两侧。
inherit; 规定应该从父元素中继承clear属性值。

浮动元素超过父盒子宽度就会自动换行
边距重合:
正常文档流的父元素里面的两个子元素在垂直方向相遇,上面的设置下边距,下面的设置上边距,两个中间的边距不会相加,只会 取最大值。
具体的叠加规则是:正正取大值、正负值相加、负负最负值
解决方法:直接给margin-bottom与margin-top其中一个元素两者之和
边距传递:
正常文档流的父元素里面的第一个子元素设置上边距时,这个上边距会传递给父级元素。
解决方法:
1、用父元素padding代替子元素margin /* 不推荐使用*/
2、父元素透明边框 border:1px solid transparent; /*不推荐使用*/
* 3、子元素绝对定位 postion:absolute;
4、父元素 overflow:hidden; (溢出隐藏) /* 可以使用 */
5、父或子元素加 float:left;
6、父或子元素加 display:inline-block; /*不推荐使用*/
7、在盒子内添加一个空的伪元素做盒内第一个元素
.bx::before{
content:'';
width:100%;
height:1px; /*设置高度为1px*/
margin-bottom:-1px; /*设置底外边框为 -1px 与高度抵消*/
display:block;
}
overflow属性规定当内容溢出元素框时发生的事情,有四个参数:
overflow: visible; 内容不会被修剪,会呈现在元素框之外,这是默认值。
overflow: hidden; 内容会被修剪,但是浏览器不会显示供查看的滚动条。
overflow: scroll; 内容会被修剪,但是浏览器会显示滚动条以便查看其余内容。
overflow: auto; 自动。由浏览器决定如何显示,如超出则会显示滚动条。


overflow-y: scroll; 设置仅在y轴的超出滚动条。


overflow: hidden;
/* 文字溢出隐藏 */
white-space: nowrap;
/* 不换行,内容在一行显示 */
text-overflow: ellipsis; /*!!!需要搭配overflow:hiddenl;使用*/
/* 溢出文字为省略号 */
word-wrap:break-word; //文字溢出换行

定位 Position

定位=定位模式 + 边偏移
position 属性指定了元素的定位类型:static; relative(相对定位) fixed(固定定位); absolute(绝对定位); sticky(粘性 定位)
static 定位 静态定位的元素不会受到 top, bottom, left, right影响

fixed(固定定位) 元素的位置相对于浏览器窗口是固定位置,即使窗口是滚动的它也不会移动:
注意: Fixed 定位在 IE7 和 IE8 下需要描述 !DOCTYPE 才能支持。
Fixed定位使元素的位置与文档流无关,因此不占据空间。
Fixed定位的元素和其他元素重叠.

relative 相对定位 他是相对于自己原来的位置来移动的,移动相对定位元素,但💖它原本所占的空间不会改变💖
例1:div
{
position:relative; /*在原来位置的基础上下移左移了30px*/
left:30px;
top:30px;
}

absolute 绝对定位 子绝父相:如果子级使用绝对定位,父级则需要相对定位。
1、自己绝对定位,💖不会占有位置💖,可以放到父盒子里面的任何一个地方,不会影响其他的兄弟盒 子,会和其他盒子重叠。
2、父盒子需要加定位限制子盒子在父盒子内显示。
3、父盒子布局时,需要占有位置,因此父亲只能是相对定位。

sticky 粘贴定位 定位表现为在跨越特定阈值前为相对定位,之后为固定定位.特定阈值指的是 top, right, bottom 或 left 之一,换言之,指定 top, right, bottom 或 left 四个阈值其中之一,才可使粘性定位生 效。否则其行为与相对定位相同



将盒子固定在版心右侧位置。
1、让固定定位的盒子left:50%,走到浏览器可视区(相当于版心)的一版位置。
2、让固定定位的盒子margin-left:版心宽度的一半距离。多走版心宽度的一般位置。


定位的叠放次序:z-index
在使用定位布局时,可能会出现盒子重叠的情况。此时,可以使用z-index来控制盒子的前后次序(z轴)
z-index:1;
1、数值可以是正整数、负整数或是0,默认是auto,数值越大,盒子越靠上
2、如果属性值相同,则按照书写顺序,后来者居上。
3、数字后面不能加单位。
4、只有定位的盒子才有z-index属性


拓展:
定位特殊性:绝对定位和固定定位也和浮动类似
1、行内元素添加绝对或者固定定位,可以直接设置高度和宽度。
2、块级元素添加绝对或者固定定位,如果不给宽度或者高度,默认大小是内容的大小。
3、浮动元素,只会压住它下面标准流的盒子,但是不会压住下面标准流盒子里面的文字(图片),但是绝对定位(固定定位)会压住下面标准流所有内容。
<div></div>
<span></span>span的字会跟在div后面
原因:浮动之所以不会压住文字,因为浮动产生的目的最初是为了做文字环绕效果的。文字会围绕浮动元素

overflow-y 指定如何处理顶部/底部边缘的内容溢出元素的内容区域
visible 不裁剪内容,可能会显示在内容框之外。
hidden 裁剪内容 - 不提供滚动机制。
scroll 裁剪内容 - 提供滚动机制。
auto 如果溢出框,则应该提供滚动机制。
no-display 如果内容不适合内容框,则删除整个框。
no-content 如果内容不适合内容框,则隐藏整个内容。
在导航栏设置无序列表,在每一行设置二级列表。一般状态二级导航为display: none;(隐藏内容)。设置一级导航的hover属性;当鼠标经过时取消隐藏。

控制鼠标经过的hove加在一级导航的div中。hover后跟要控制的元素 例:
.div1:hover ul{ /*鼠标经过.div1元素时,控制的元素是ul*/
display: block;
}
旋转 transform: rotate(*deg);

倾斜 transform: skew(); skewX / skewY

平移 transform:translate(); X / Y

缩放 transform: scale(); X,Y

平滑过渡 transition: 1s; //全部平滑过渡 transition: all 1s;
//若要单个控制平滑 transition: width 1s; (单独控制宽度的平滑时间)





position: absolute;
top:50%;
left:50%;
transform: translate(-50%,-50%);
/*将页面移到中央*/
添加动画:1.			@keyframes 动画名 {
from{}
to{}
}
2. @keyframes 动画名 {
0%{
}
50%{
}
100%{
}
}
绑定动画: animation: 动画名 动画持续时间 延迟多少时间播放 动画重复次数(infinite持续播放)(linear匀速播放) 动画结束位置(forwards留在原位);
animation-name: example; 动画名
animation-duration: 5s; 动画时间
animation-timing-function: linear; 规定速度曲线(linear匀速 ease慢块慢 ease-in慢速开始 ease-out慢速结束 ease-in-out慢速开始和结束 cubic-bezier(n,n,n,n)0 到 1 的数值)
animation-delay: 2s; 动画延迟
animation-iteration-count: infinite; 播放次数(持续播放 infinite;)
animation-direction: alternate; 向前播放、向后播放还是交替播放





注意:使用移动动画的元素必须添加相对定位
动画延迟可以为负值,动画则为从已播放的 N 秒开始

fiex布局

注意,设为 Flex 布局以后,子元素的float、clear 等属性将失效。
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)
主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end
项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size
项目默认沿主轴排列。单个项目占据的主轴空间叫做main size(项目宽度),占据的交叉轴空间叫做cross size(项目高度)



弹性盒子内一般不设置死的宽高(突出弹性的特点)
子元素设置flex:1;即可铺满盒子 (若不给死宽高使用比例,则需要没有死宽高的子元素都设置比例)

设置在父盒子的属性

以下6个属性设置在父容器上。
* flex-direction :主轴方向
* flex-wrap :是否换行,怎么换行
* flex-flow :flex-flow 属性是 flex-direction 和 flex-wrap 属性的复合属性。
* justify-content: 属性定义了项目在主轴上(X)的对齐方式。
* align-items:属性定义项目在交叉轴上(Y)如何对齐。
* align-content:属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。


*flex-direction属性值
row(默认值):(X)主轴为水平方向,起点在左端。
row-reverse:(X)主轴为水平方向,起点在右端。
column:(Y)主轴为垂直方向,起点在上沿。
column-reverse:(Y)主轴为垂直方向,起点在下沿。

*flex-wrap属性值
nowrap(默认):不换行。(项目总宽度如果超出盒子宽度,项目宽度会被挤压【不会超出盒子】)
wrap:换行,第一行在上方。
wrap-reverse:换行,第一行在下方。

*flex-flow属性
flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为 nowrap
flex-flow:flex-direction flex-warp;

*justify-content属性
justify-content属性定义了项目在主轴上(X轴)的对齐方式
flex-start(默认值):左对齐
flex-end:右对齐
center: 居中
space-between:两端对齐,项目之间的间隔都相等。
space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。(项目之间的间隔为左右两个项目间隔之和)
space-evenly 间隔相等

*align-items属性
align-items属性定义项目在交叉轴上(Y轴)如何对齐
flex-start:交叉轴的起点对齐。(上端对齐)
flex-end:交叉轴的终点对齐。(下端对齐)
center:交叉轴的中点对齐。(上下居中)
baseline: 项目的第一行文字的基线对齐。
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

*align- content属性
align- content属性定义了行的对齐方式。如果项目只有一根轴线,该属性不起作用。
该属性中的六个属性值与justify-content中的六个属性意思相似,不同之处在于justify-content沿主轴方向的作用于单个子元素,而align-content沿交叉轴方向作用于行。
flex-start:与交叉轴的起点对齐。(所有项目上对齐)
flex-end:与交叉轴的终点对齐。(所有项目下对齐)
center:与交叉轴的中点对齐。(所有项目上下居中,上下项目间没间隔)
space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。(所有项目上下排满,项目间有间隔,项目间间隔为两个单项目间隔)
space-around:每根轴线两侧的间隔都相等。所以轴线之间的间隔比轴线与边框的间隔大一倍。()
stretch(默认值):轴线占满整个交叉轴。(项目若没设高则会拉长占满)

设置在项目上的属性(子元素上)

*	order : 属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。
* flex-grow: 属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
* flex-shrink: 属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
* flex-basis: 属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
* flex: 属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
* align-selff:属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch

*order属性
属性值一般为number类型也可以是initial(默认值),inherit(从父元素继承的值)为设置弹性盒对象元素的顺序:数字越小越靠前。取值0.1.2...

*flex-grow属性
如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

*flex-shrink属性
属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小

*flex-basis属性
定义了在分配多余空间之前,项目占据的主轴空间(main size)相当于宽度,优先级大于自身设定的宽度。

* flex属性
是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
flex:1;0占有空间 ,1缩放比例,100px固定值
这个0 1 auto是什么意思,
flex-grow:表示当子元素的空间小于父元素的空间时,如何处理剩余空间,默认值为0表示不占有剩余空间;
felx-shrink:表示当子元素的空间大于父元素的空间时,如何缩小子元素,默认值为1表示等比缩小
flex-basis :用于设置项目占据的主轴空间,设置为auto表示项目占据的主轴大小等于项目的实际内容大小,设置为固定值表示项目占据的主轴大小等于固定值

*align-self属性
允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性(优先级高)。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。


flex-shrink: 0;被压缩比例(设置为0不会被压缩)

移动端布局(响应式)

*	视口:视口(viewport)就是浏览器显示页面内容的屏幕区域,视口可以分为视觉视口,布局视口和理想视口
* 布局视口:布局视口是指网页的宽度,一般移动端浏览器都默认设置了布局视口的宽度。移动端浏览器之所以采用这样的默认设置,是为了解决早期的PC端页面在手机上显示的问题。根据设备的不同,布局视口的默认宽度有可能是768px、980px或1024px等,这个宽度并不适合在手机屏幕中展示。(当移动端浏览器展示PC端网页内容时,由于移动端设备屏幕比较小,不能像PC端浏览器那样完美地展示网页,这正是布局视口存在的问题。这样的网页在手机的浏览器中会出现左右滚动条,用户需要左右滑动才能查看完整的一行内容)
* 视觉视口:用户正在看到的网站区域。可以通过缩放操作视觉视口。但不会影响布局视口,布局视口依然保持原来的宽度。
* 理想视口:理想视口是指对设备来讲最理想的视口尺寸。采用理想视口的方式,可以使网页在移动端浏览器上获得最理想的浏览和阅读的宽度。在理想视口情况下,布局视口的大小和屏幕宽度是一致的,这样就不需要左右滚动页面了。在开发中,为了实现理想视口,需要给移动端页面添加标签配置视口,通知浏览器来进行处理。

meat视口标签

<meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0"/>
name=“viewport”:意为视口标签
Content:里边包裹的若干属性
标准的写法:
width:视口的宽度可以,设置特殊值device-width宽度是设备的宽度
initial-scale:初始化缩放倍数 一般是大于0数字
user-scalable:是否允许用户自行缩放,取值0或1,yes或no
maximum-scale:最大缩放(一般是大于0数字)允许放大的倍数
minimum-scale:最小缩放(一般是大于0数字)允许缩小的最大倍数
物理像素点指的是屏幕显示的最小颗粒,是物理真实存在的。 这是厂商在出场时就设置好了(也就是我们的分辨率),
我们开发时候的1px不一定等于一个物理像素
PC端页面 1个px等于一个物理像素 但是移动端就不一样
一个px能显示的物理像素点的个数 称为物理像素比或屏幕像素比
对于一张 50px * 50px 的图片,在手机Retina(视网膜)屏中打开 按照原本的物理像素比会放大倍速 这样会造成图片模糊在标准的viewport设置中 使用倍图来提高图片质量 解决在高清设备中的模糊问题一般都是使用二倍图 ,但因为手机屏幕的影响 现在还存在三倍四倍图的情况背景图片注意缩放

移动端开发的选择

1.单独制作移动端页面(主流)
流式布局(也就是百分比布局)
Flex布局(推荐)
rem适配布局
混合布局(我们日常的布局方式就叫混合布局)

rem单位 rem(root em)是一个相对单位,类似于em,em是父元素字体大小。不同的是rem的基准是相对与html元素的字体大小。比如,根元素(html)设置font-size=12px;非根元素设置width:2rem;则会换成px表示就是24px。优势:可以通过修改html里面的文字大小来改变页面中元素大小,可以整体控制。rem是html与单个元素的比例单位,em是父元素与子元素的比例单位。

* rem的适配方案
<1>.媒体查询+rem方案
<2>.rem.js+rem

(媒体查询限制CSS样式的范围,以便于在满足某些媒体条件时才适用。简单来说:媒体查询可以让我们根据设备显示器的特性(如视口宽度、屏幕比例、设备方向:横向或纵向)为其设定CSS样式。

* 它都有那些媒体类型
All(所有设备)
Print(打印设备)
Screen(电脑,笔记本,手机等设备)
* 它都有那些媒体特性
width 网页显示区域完全等于设置的宽度
height 网页显示区域完全等于设置的高度
max-width / max-height 网页显示区域小于等于设置的宽度
min-width / min-width 网页显示区域大于等于设置的宽度
orientation: portrait (竖屏模式) | landscape (横屏模式)

* 语法关键字,将媒体特性与媒体类型链接到一块进行设备检测
and 可以将多个媒体特性链接到一块,相当于且
not 排除某个媒体特性 相当于非,可以省略
only 指定某个特定的媒体类型, 可以省略


* 媒体查询有两种语法
外联语法:<link rel="stylesheet" type="text/css" media="only screen and (max-width:750px)" href=""/>
内嵌式语法:
@media screen and (min-width:320px){
html{
font-size: 21.33px;
}
}

* 外联语法:
<link rel="stylesheet" type="text/css" media="only screen and (max-width:350px)" href=“css350.css"/>

<link rel="stylesheet" type="text/css" media="only screen and (max-width:750px)" href=“css750.css"/>

* 内嵌语法:
@media screen and (min-width:320px){
body {
background:#000;
}
}
@media screen and (min-width:750px){
body{
background:#f99;
}
}




2制作响应式页面兼容移动端(其次)
就是通过媒体查询  限制屏幕的宽度 然后根据不同的宽度写不同的代码

移动端PC端转换

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

/*pc 移动都添加到scipt标签中(位置在body下面)*/


// 摘要:控制不同尺寸屏幕上的rem基准单位
// 以iPhone6位基准 375px 最大适配750px 屏幕
var maxAdaptation = 750
document.addEventListener('DOMContentLoaded', function () {
var deviceWidth = document.documentElement.clientWidth > maxAdaptation ? maxAdaptation : document.documentElement.clientWidth
document.documentElement.style.fontSize = (deviceWidth / 15) + 'px'
var funID
window.onresize = function () {
clearTimeout(funID)
funID = setTimeout(function () {
var deviceW = document.documentElement.clientWidth > maxAdaptation ? maxAdaptation : document.documentElement.clientWidth
document.documentElement.style.fontSize = (deviceW / 15) + 'px'
}, 500)
}
}, false)



/*只添加在移动端*/

添加下划线的方法

1.元素名::after{
content:'';
height:2px;

display:block;
}
2.div{
border-bottom:宽度 样式 颜色;
}

以下属性使用时必须配合定位

使用动画时配合相对定位
z-index;调整显示优先级时必须使用定位

JS基本知识

一个完整的javascript实现应该有三个部分构成:ECMAScript、DOM、BOM
javascript特点:1.解释型语言(不进行编译,不用转换成二进制的计算机语言)2.动态型语言(是一类在运行时可以改变其结构的语言)
JS能够做什么:
能改变页面中的所有 HTML 元素
能改变页面中的所有 HTML 属性
能改变页面中的所有 CSS 样式
能删除已有的 HTML 元素和属性
能添加新的 HTML 元素和属性
能对页面中所有已有的 HTML 事件作出反应
能在页面中创建新的 HTML 事件

JS外部引入

1、<script src=‘’xxxxx.js“></script>引入
2、脚本可被放置与 HTML 页面的 <body> 或 <head> 部分中,或兼而有之。
3、把脚本置于 <body> 元素的底部,可改善显示速度,因为脚本编译会拖慢显示。
声明变量: var name ;
var 是一个js关键字,用来声明变量的,使用var关键字声明变量后,计算机会自动为变量分配内存空间,不需要程序员管理

JS输出方式

Js的输出方式:
alert(msg):弹出框
console.log(msg):打印日志(consol方法不止一个)
prompt(msg):输入框 注意:输入类型为字符串
例:输入班级人数与每个人分数求和
var a = prompt('请输入班级总人数')
var sum = 0
for(var i = 1;i<=a;i++){
var b = Number( prompt ('请输入第' + i + '位同学的分数'))//进行强制类型转换将输入的字符串转换为Number
sum = sum + b
}
console.log(sum)

基本数据类型

JS 把数据类型分为两类: 
简单数据类型 (Number String Boolean Undefined Null)

复杂数据类型 (数组、object、function...)//数组属于object(对象)

三种对象类型:
对象(Object)\ 日期(Date)\ 数组(Array)

* Number 数字型,包含整型和浮点型值 默认值:0
* Boolean 布尔值类型,true\false 等价于1\0
* String 字符串类型 注意:在JS中,字符串都带有引号
* Undefined 声明变量但是没有给变量赋值,此时 变量=undefined
* Null 声明变量为空值

简单数据类型
数字型范围:
* 最大值:Number.MAX_VALUE,这个值为: 1.7976931348623157e+308
* 最小值:Number.MIN_VALUE,这个值为:5e-324

三个特殊值:
* Infinity ,代表无穷大,大于任何数值
* -Infinity ,代表无穷小,小于任何数值
* NaN ,Not a number,是计算机科学中数值数据类型的一类值,表示未定义或不可表示的值。常在浮点数运算中出现


字符串型 String
var a = '我是帅哥'
var a = "我是帅哥"
注意:因为 HTML 标签里面的属性使用的是双引号,JS 这里我们更推荐使用单引号

JS 可以用单引号嵌套双引号 ,或者用双引号嵌套单引号 (外双内单,外单内双)不能单双引号搭配


Undefined
声明后没有被赋值的变量会有一个默认值 undefined ( 如果进行相连或者相加时,注意结果)
例:
var a;
console.log(a); // undefined
console.log('你好' + a); // 你好undefined
console.log(11 + a); // NaN
NaN console.log(true + a); // NaN

null
一个声明变量给 null 值,里面存的值为空
例:
var q = null;
console.log('你好' + q); // 你好null
console.log(11 + q); // 11
console.log(true + q); // 1







转义符:
\n 换行
\ 代码中换行使用(在行尾添加)
\' 单引号
\" 双引号
\t tab缩进
\b 空格

字符串长度
通过字符串的 .length 属性可以获取整个字符 串的长度
var a = '我他妈是帅哥'
alert(a.length)
输出值为6

字符串拼接
中间必须有+ 变量不加引号(添加引号变字符串)

字面量
字面量是在源代码中一个固定值的表示法,通俗来说,就是字面量表示如何表达这个值。
var  a = 1;//这里的1就是字面量

typeof ( ) 方法

获取检测变量的数据类型				******属于运算符
typeof 可用来获取检测变量的数据类型
例:
var n = 18;
console.log(typeof n) // 结果 number
不同类型的返回值:
typeof 运算符把类型信息当作字符串返回。
* 他有两种用法
1.typeof 变量名
2.Typeof(表达式)

typeof 返回值有六种可能: "number," "string," "boolean," "object," "function," 和 "undefined“
但是我们还有中基本数据类型 null 它的typeof null 的结果是object 历史遗留问题,这是它底层的一个bug
转换为字符串类型
三种办法
toString() // var a=1; a.toString()
String()强制转换 // var a=1;String( a )
加号拼接字符串 //var a=1; a+=‘我是字符串’

toString() 和 String() 使用方式不一样。 toString(): 无法转换null和undefined
三种转换方式,我们经常用第三种加号拼接字符串转换方式, 这一种方式也称之为隐式转换。

转换成数字型
parseInt(‘78’)将字符串准换成整数数值型
parseFloat(‘7.21’)将字符串准换成浮点数数值型
Number(‘78’)将字符串准换成数值型(强制转换)
‘12’-0(隐式转换)
注意 parseInt 和 parseFloat 单词的大小写,这2个是重点
隐式转换是我们在进行算数运算的时候,JS 自动转换了数据类型

转换为布尔型
转换的方法 Boolean(‘你好’)
代表空、否定的值会被转换为 false ,如 ''、0、NaN、null、undefined
其余值都会被转换为 true


隐式类型转换存在那些地方(隐式转换的规则)
1. 转成string类型: +(字符串连接符)
2. 转成number类型:++/--(自增自减运算符) - * / % (算术运算符) > ,< ,>= ,<= ,== , != ,=== , !== (关系运算符)

3. 转成boolean类型:!(逻辑非运算符)



其他注意事项:
标识符 标识符:就是指开发人员为变量、属性、函数、参数取的名字。 标识符不能是关键字或保留字。
关键字:是指 JS本身已经使用了的字,不能再用它们充当变量名、方法名。例如:break、case、catch、continue、default、delete、do、else、finally、for、function、if、in、 instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with 等
保留字 保留字:实际上就是预留的“关键字”,意思是现在虽然还不是关键字,但是未来可能会成为关键字,同样不 能使用它们当变量名或方法名。例如:boolean、byte、char、class、const、debugger、double、enum、export、extends、 fimal、float、goto、implements、import、int、interface、long、mative、package、 private、protected、public、short、static、super、synchronized、throws、transient、 volatile 等
算数运算符 
递增和递减运算符
比较运算符
逻辑运算符
赋值运算符

NaN 与任何值进行运算结果都为NaN

+有一种特殊情况,当字符串与其他数据类型进行+运算时,会进行字符串拼接

浮点数精度问题
var result = 0.1 + 0.2; // 结果不是 0.3,而是:0.30000000000000004
console.log(0.07 * 100); // 结果不是 7, 而是:7.000000000000001
所以:不要直接判断两个浮点数是否相等 !

++a 不能单独打印,会先运行打印a 再自增。
a++ => 返回的值是a本身
++a => 返回的值是a+1后的值
开发时,大多使用后置递增/减,并且代码独占一行,例如:num++; 或者 num--;



全等运算符 === 要求值和数值类型都一致

区别:
= 赋值 右边值给左边
== 判断 判断两边值是否相等(注意此时有隐式转换)
=== 全等 判断两边值与数据类型均相等

逻辑运算符
&& 与 || 或 ! 非
逻辑非 ! :也叫作取反符,用来取一个布尔值相反的值,如 true 的相反值是 false(返回值为布尔类型,自然数为true,其余均为false)

运算符优先级:
一元运算符中逻辑非优先级最高
逻辑与比逻辑或优先级高

字符串拼接

var a = ''
for(var i = 1 ;i<=9 ;i++){
for(var j = 1; j<=i ; j++){
a = a + j + '*' + i + '=' + i*j + '\t' //字符串拼接
}
a += '\n' //字符串拼接
}
console.log(a)

九*九 乘法表
注意字符串拼接方法
拼接后a变量中存放的均为字符串:1*1=2\t\n2*2=4....

字符串部分方法

length长度属性
查找字符串
indexOf () 方法返回字符串中指定文本首次出现的索引(位置): 传入两个值,(第一要查找的目标,起始位置)
lastIndexOf()
如果未找到文本, indexOf() 和 lastIndexOf() 均返回 -1。 传入两个值,(第一要查找的目标,起始位置)
search() 方法搜索特定值的字符串,并返回匹配的位置
search() 方法无法设置第二个开始位置参数。
indexOf() 方法无法设置更强大的搜索值(正则表达式)。

提取部分字符串
slice () 切割字符串 该方法设置两个参数:起始索引(开始位置),终止索引(结束位置)。 不包含结束索引 掺传入负值为反着拿值
substring() 切割字符串 该方法设置两个参数:起始索引(开始位置),终止索引(结束位置)。 不包含结束索引 不可传入负值
substr() 切割字符串 该方法设置两个参数:起始索引(开始位置),截取字符串长度。 不包含结束索引


将字符串转为数组:
eval方法
k 为带 [ ] 的数组样式字符串 (JSON方法不可用时)
k = eval('('+k+')')


替换字符串
replace (‘传入要被替换的值’,‘要更换的新值’)
toUpperCase() 字符串转换为大写:
toLowerCase() 字符串转换为小写:
concat() 连接两个或多个字符串:
trim() 方法删除字符串两端的空白符
charAt() 方法返回字符串中指定下标(位置)的字符串:
charCodeAt() 方法返回字符串中指定索引的字符 unicode 编码:
split () 将字符串转换为数组:
toLocaleUpperCase () 字符串转换为大写:
toLocaleLowerCase () 字符串转换为小写:
浏览器打开页面 → 按f12打开开发者工具 → 打开Sources → 打开你要调试的js代码文件 → 在想查看的地方的行号上单击一下→在刷新页面 → f11
watch:监视,通过watch可以监视变量的值的变化
F11:程序单步执行,也就是一行一行的执行,这个时候,观察watch中变量值的变化
很总要,学会调试也就获得了查找bug的能力

for循环

for循环语法
for(初始化变量; 条件表达式; 操作表达式 ){//条件表达式为true,会一直执行
循环体
}

for(表达式1){
for(表达式2){
}
}

While循环

While(表达式){    //满足条件进入循环,当值为true时为死循环,false时终止循环/break打断循环
}
//先判断再循环

创建一个whlie循环也需要3个步骤
1.初始化一个变量 (只执行一次)
var a = 0;
2.在循环体中设置一个条件表达式
while(a > 10){
3.定义一个更新表达式
a++
循环体执行一次a变量更新一次,
}

do...while循环

do{          
语句
}while(条件表达式){
语句
}
//两者执行的流程不同do..while语句在执行时,先执行循环体,后判断
//能保证这个循环体至少执行一次
// !!!注意:while条件表达式中值为true时循环,值为false时结束循环.条件为真的话,就会重复这个循环
//陷入无限循环的两个条件:
// 1.条件判断始终为true
// 2.使用变量作为条件,未设置在循环中自然增长,则会出现无限循环

switch..case 循环

switch (表达式){
case value1:
statements1 // 当表达式的结果等于 value1 时,则执行该代码
break;
case value2:
statements2 // 当表达式的结果等于 value2 时,则执行该代码
break;
......
case valueN:
statementsN // 当表达式的结果等于 valueN 时,则执行该代码
break;
default :
statements // 如果没有与表达式相同的值,则执行该代码
}

//注意:switch 语句中,表达式是使用全等(===)来与各个 cese 子句中的值进行匹配的。由于使用的是全等运算符,因此不会自动转换每个值的类型。
break 语句“跳出”循环。直接跳出不再执行后边的循环

continue 语句“跳过”循环中的一个迭代。后边的循环继续执行

数组遍历forEach()

方法对数组的每个元素执行一次给定的函数。

只传入一个函数作为参数

let arr = ['a','b','c','d']
arr.forEach(myfun);
function myfun(item,index){
console.log(item,index)
}
// 'a' 0
// 'b' 1
// 'c' 2
// 'd' 3

数组 Array

创建数组的两种方式:
1.利用 new 创建数组
2.利用数组字面量创建数组(常用) // var 数组名 = []
通过new关键字创建数组:
var 数组名 = new Array() //Array 严格区分大小写

数组中可以存放任意类型的数据

可以利用循环来遍历数组

数组名.length //访问数组长度





//注意!!!当两个数组进行传值的时候用slice()方法可以避免'指针'问题

数组的常用方法

数组中的常用四种方法:
1.向数组的最后一位添加一个或者多个新的元素,并反回长度
push方法
数组.push()
2.pop方法
可以删除数组的最后一位并返回
数组.pop()
3.unshift方法
可以向数组第一位添加一个或多个新的元素,并返回长度
数组.unshift()
4.shift方法
可以删除数组中第一位,并返回
数组.shift()
5.splice方法//删除/插入
可以删除数组中的某一位
数组.splice//(第几位,删除几个值)
数组.splice(2,0,'abc')//在第二位,删除0个值,插入abc
6.slice方法//复制数组的一部分,!!!用slice方法复制的新数组可以避免'指针'的问题
返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象
举例:var n =[0,1,2,3,4,5,6,7,8,9]
var a = n.slice(2,5)
console.log(a)//a数组为[2,3,4]
7.concat()方法//拼接数组
拼接两个数组
举例:
var arr = [1,1,1]
var arry = [2,2,2]
ar = arr.concat(arry)//ar数组为[1,1,1,2,2,2]
8.join()方法//变为字符串
把数组中的所有元素放入一个字符串,元素是通过指定的分隔符进行分隔的//注意:返回值为字符串
举例:
var x = [1,1,1]
var y = x.join()//括号内为分隔符,默认为 ,
9.reverse()方法//改变原数组,颠倒顺序
可以颠倒数组中元素的顺序
var n = [1,2,3]
n.reverse()//数组变为[3,2,1]
10.sort()方法//数组从小到大顺序排序(注意:根据UTF-16代码单元值进行排序,只能排序十以内的数字)



* 用于确定传递的值是否是一个 Array(判断它是不是个数组) 返回false或者true
Array.isArray(表达式/变量)


将伪数组转化为标准数组

Array.prototype.slice.call(伪数组名)

普通排序与冒泡排序


***//举例:数组去重
    var n = [1, 2, 3, 4, 5, 6, 7, 8, 9, 5, 3, 1, 5, 6, 7, 3, 3, 3]

    for(var i = 0 ;i< n.length; i++){
        for(var j = i+1 ; j<n.length; j++){
            if(n[i] == n[j] ){ //如果值相等,删除后面的值
                n.splice(j,1)
                j--
            }
        }
    }
    console.log(n)          //数组重复数字删除






***//举例:数组去重、冒泡排序:
var n = [6,3,5,9,0,5,7,6,1,4,2,3,6,7,8,5,4,3,9,0]

    for(var i = 0 ;i< n.length; i++){
        for(var j = i+1 ; j<n.length; j++){
            if(n[i] == n[j] ){
                n.splice(j,1)
                j--
            }
        }
    }
    console.log(n)          //数组重复数字删除
//冒泡
for(var i = 0 ; i< n.length-1;i++){//-1是因为大的数已经排在后面了,最前面的数已经是最小的了,不用再排一遍
    for(var j = 0 ;j < n.length-i-1;j++ ){// -i是因为冒泡排序排在后面,后面的顺序已经排完,不用再参与排序;-1是因为if中有+1,在此补上
        if(n[j] > n[j+1]){//比较相邻两数大小,如果后值较大,交换相邻两数位置
            var k = ''
            k = n[j+1]
            n[j+1] = n[j]
            n[j] = k
        }
    }
                        //数组排序
}
console.log(n)




***//普通排序
var arr = [5, 7, 9, 6, 3, 4, 2, 1, 8]
for (var i = 0; i < arr.length - 1; i++) {//j为i+1,省去一次循环步骤
for (var j = i + 1; j < arr.length; j++) {//在内循环中,i始终没变,相当于前面的数与后面每一个比较
if (arr[i] > arr[j]) {//当前下标为i的值与当前下标为j的进行比较,如果大于就准换位置
sun = arr[i]//第三方变量存储值并更换值
arr[i] = arr[j]
arr[j] = sun
}
}
}
console.log(arr)

对象 Object

在JS中,对象是一组无序的相关属性和方法的集合。//对象是由属性和方法组成的

创建对象的三种方法

1. var 对象名 = new Object()	//严格区分大小写
2. var 对象名 = {}
3.构造函数

对象的调用

1.对象名.name//取值,调用(仅返回值)
2.对象名[‘name’] //取值,调用(仅返回值)

给对象插入属性

注意,对象中每条属性用 , 隔开

1.对象名.属性名 = '属性值' //属性值为字符串时要加 ''
举例:
ls.name = '李硕', //每加一条属性后要加 ,
2. var ls{}
ls.name = 'lishuo',
var a = 'age' //创建一个变量值为属性名(必须为字符串)
ls[a] = 18 //添加属性 age = 18

遍历对象的方法

entries()

Object.entries() 方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致( 区别在于 for-in 循环还会枚举原型链中的属性)

var obj = {
name:'lishuo',
age:22
}
console.log(Object.entries(obj))
// ['name', 'lishuo']
// ['age', 22]
//返回为数组


var obj = {
name: 'lishuo',
age: 22
}
for (const [key, value] of Object.entries(obj)) {
console.log(`${key}: ${value}`);
}
// name: lishuo
// age: 22
//返回为字符串

冻结对象和属性

var constantize = (obj) => {
Object.freeze(obj);//冻结对象
Object.keys(obj).forEach( (key, i) => {//冻结对象内的属性
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};

函数 Function

在开发过程中,部分代码会被重复使用,函数可把代码封装起来重复使用

函数语法:
function 函数名(形参){
代码段
}
调用:函数名(实参)


如果实参个数多于形参,形参将按照顺序依次接收实参,剩余的值不被接收
如果实参个数少于形参,形参将按照顺序依次接收实参,多于的形参接收不到实参,默认值为undefined


//函数中的return语句的两个作用:
1.函数中通过return关键字指定返回值
2.结束当前函数,不在继续向下执行代码//注意:return后的语句不再执行
3.如果没有指定返回值,则函数默认返回值为undefined



arguments 对象

//函数中的arguments对象:(它的行为就像数组)
当不确定有多少个参数传递的时候,可以用arguments来获取,在js中,arguments实际上它是当前函数的一个内置对象,所有的函数都有一个内置的arguments对象,arguments对象中储存了传递的所有实参//(当实参是否大于形参,实参都会储存在arguments中)
//arguments对象特点:
1.arguments的展示形式是一个伪数组,具有数组的特点,但是不可以使用数组的方法,因此可以进行遍历
2.伪数组的特点(数组的特点)
具有length属性
按照索引方式存储数据
不具有数组的push,pop等方法

局部变量与全局变量

	在函数内部声明的变量叫做局部变量,在函数外部的变量叫做全局变量

变量提升:将局部变量该变为全局变量//提升方法:在函数中声明新变量时不使用var 直接使用变量
当js执行的时候,发现你的字段未被声明,js会向顶端自动补充声明


作用域:
* 全局作用域:整个script标签或是某一个单独的js文件
* 局部作用域:在函数内部的就是局部作用域,这个代码或者名字只能在函数内部起效果和作用

作用域链:
* 在某个作用域中访问某个变量时,如果当前作用域中没有该变量,则会依次向上访问上层的作用域的变量

try...catch

try...catch 捕捉到错误后仍可继续运行

构造函数通俗含义:对象的创造工厂//通常函数名首字母都会大写
构造函数与普通函数的区别在于构造函数有 this
this 只在 new 时使用
例:
function Man(a,b,c){
this.name = a; //this 指向新定义的变量空间(this 指向 变量lishuo 的空间,为 lishuo 添加属性)
this.age = b;//实例成员
this.sex = c;
this.fn = function(){//复杂类型(所有实例化成员中都会有fn方法,需要被调用才会执行)
//注意:这样的方法只是他自己的方法,不可以继承
console.log('敲代码')//注意:虽然实例化成员调用函数都会输出'敲代码',但是对象间的'敲代码并不相同'
}
}
var lishuo = new Man('李硕',18,'男') //变量lishuo 中储存了一个对象,也可以说 变量lishuo就是一个对象。 new的返回值为对象,所以构造函数不需要return
Man.height = '60' //静态成员,是添加给Man的属性,不影响实例化成员

new 在执行时会做四件事情:
(1)在内存中创建了一个新对象。
(2)让this指向这个新的对象
(3)通过执行构造函数里边的代码,给这个新对象添加属性和方法。
(4)返回这个新对象(所以构造函数不需要return)



构造函数
构造函数中可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数内部的 this 上添加,通过这两种方式添加的成员,就分别称为静态成员和实例成员。
//静态成员与实例成员只影响构造函数
静态成员:在构造函数本身添加的成员叫做静态成员。静态成员只能通过构造函数进行访问,不能通过对象访问。
实例成员:在构造函数内部通过this添加的成员叫做实例成员。实例成员只能通过实例化对象进行访问,不可以通过构造函数访问
//实例化对象只能调用实例成员
//构造函数只能调用静态成员

构造函数的原型对象 prototype

构造函数通过原型分配的函数是所有对象的共享的// !!! prototype是一个对象
每一个构造函数都有一个prototype属性,指向另一个对象(构造函数下面的对象),注意这个 prototype 就是一个对象,这个对象的所有属性和方法都会被构造函数所拥有(可以被构造函数下的实例化对象拥有)
可以把一些不变的方法,直接定义在prototype对象上,这样所有的实例化对象可以共享这些方法了

//prototype 也是构造函数中的一个实例成员
举例:
function Man(name,sex,age){ //构造函数
this.name = name//实例成员
this.age = age
this.sex = sex
}
//原型对象 prototype

Man.prototype = {
fn1:function(){
console.log('敲代码')
},
height:180,
fn2:function(){
console.log('吃饭')
},
fn3:function(){
console.log('打豆豆')
},
constructor:Man //
}
//Man.prototype.weight = '70kg'
//给prototype添加的属性,实例化对象都会继承
var xz = new Man('小猪','男',18)
var kk = new Man('康康','男',20)
var jj = new Man('静静','女',2)

xz.fn4()
jj.fn1()

实例化对象的 proto 属性

*	实例化对象 身上的  _proto_属性,指向公共的prototype
* 对象身上系统自动添加了一个_proto_指向了 构造函数的prototype原型对象
查找规则:首先看实例化对象身上有没有这个属性(实例化对象单独添加的),如果有就执行这个属性,如果没有就通过_proto_属性去查找构造函数的原型对象(prototype)有没有这个属性

实例化对象.__proto__ === 构造函数.prototype

在 原型对象(prtotype) 和 对象原型 (proto) 中的constructor

constructor 属性返回所有 JavaScript 变量的构造器函数
* 在原型对象中和对象原型中的constructor属性指向生成他们的构造函数(在prototype对象中)
* 但是原型对象被修改覆盖后constructor就被覆盖了,我们也就不知道他构造函数是谁了,所以在覆盖的时候我们重新创建一个constructor并让他指向了自己的构造函数
在覆盖的prototype对象中加入 constructor:构造函数
__proto__\prototype\constructor\new\this

constructor 在prototype(原型对象)里面,指向构造函数的
prototype 是构造函数中给实例化对象公共的继承对象
this 指向实例化对象空间
new 指向构造函数
__proto__ 在实例化对象中指向prototype(原型对象)

对象由函数生成
对象有__proto__属性,函数有prototype属性
生成对象时,对象的__proto__属性指向函数的prototype属性

Math对象

Math 不是构造函数。Math 的所有属性/方法都可以通过使用 Math 作为对象来调用,而无需创建它
Math.abs() 求绝对值
Math.max() 求最大值
Math.min() 求最小值
Math.ceil() 函数返回大于或等于一个给定数字的最小整数(向上取整)
Math.floor()可以理解为向下取整
Math.random()打印大于等于0且小于1的随机数
Math.round(3.1415926)四舍五入
Math.trunc() 返回数字的整数部分
Math.cbrt(x) 返回 x 的三次方根
Math.sign(x) 返回数的符号(检查它是正数、负数还是零)
Math.random() 返回0-1之间的随机数


// function fn (a1,a2){
// for(var i = 0;i<100 ; i++){
// var num = Math.floor( Math.random()*(a2-a1+1)+a1 )
// console.log(num)
// }
// }
// fn( 5,10 ) 求100个 a1 到 a2 之间的随机数 (包含a1、a2)

Date 对象

日期对象是用 new Date() 创建的
日期对象是静态的。计算机时间正在滴答作响,但日期对象不会
将日期存储为自 1970 年 1 月 1 日 00:00:00 UTC(协调世界时)以来的毫秒数


实例化日期有四种方式:
var d = new Date();
var d = new Date(milliseconds);//毫秒
var d = new Date(dateString);//日期字符串,日期中间用分隔符连接,月份日期为单数时前面加0 ,02月
var d = new Date(year, month, day, hours, minutes, seconds, milliseconds);

//注意:月份、星期等 计算从0月、星期0开始

// 例:
// var d = new Date(2018, 11, 24, 10, 33, 30, 0);
// 7个数字分别指定年、月、日、小时、分钟、秒和毫秒(按此顺序)
//6个数字指定年、月、日、小时、分钟、秒 以此类推 2个数字指定年份和月份 但是不能只提供一个参数,不然会被视为毫秒


日期获取方法://var a =
getDate() 以数值返回天(1-31)
getDay() 以数值获取周名(0-6)
getFullYear() 获取四位的年(yyyy)
getHours() 获取小时(0-23)
getMilliseconds() 获取毫秒(0-999)
getMinutes() 获取分(0-59)
getMonth() 获取月(0-11)
getSeconds() 获取秒(0-59)
getTime() 获取时间(从 1970 年 1 月 1 日至今)

日期获得方法://var a =
setDate() 以数值(1-31)设置日
setFullYear() 设置年(可选月和日)
setHours() 设置小时(0-23)
setMilliseconds() 设置毫秒(0-999)
setMinutes() 设置分(0-59)
setMonth() 设置月(0-11)
setSeconds() 设置秒(0-59)
setTime() 设置时间(从 1970 年 1 月 1 日至今的毫秒数)

/* 例:
var date = new Date()
var a = date.getFullYear() //获取四位的年(yyyy)
console.log(a) */


/* 例:
var endtime = new Date("2021/11/11");//定义结束时间标准时间
var setitem = new Date()//获取当前的标准时间
// 获取时间戳 getTime() 单位毫秒

var item = endtime.getTime() - setitem.getTime()
leftd = Math.floor(item/(1000*60*60*24)), //计算天数
lefth = Math.floor(item/(1000*60*60)%24), //计算小时数
leftm = Math.floor(item/(1000*60)%60), //计算分钟数
lefts = Math.floor(item/1000%60); //计算秒数
var a = leftd + "天" + lefth + '小时' + + leftm + "分钟" + lefts + '秒'; //返回倒计时的字符串
console.log(a) */

setInterval():按照指定的周期(以毫秒计)来调用函数或计算表达式。方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。

注意:一般计时器用完后需要关闭计时器 clearInterval ( 计时器名 )

关闭计时器后最好再清空计时器

item = setInterval ( , ) //设置计时器

clearInterval ( item ) //关闭计时器

item = null //清空计时器

格式:setInterval ( 重复操作 , 间隔时间 )

计时器为window对象下的

var a = 1
var fn = null
var fn = setInterval(function(){//执行方法
console.log(10)
a++
if(a == 10){
clearInterval(fn)
}
},1000)//间隔1s

//计时器中重复操作不能调用函数,写函数变量名(变量内存中储存着函数操作)
//计时器创建前先初始化计时器


例:
left.onclick =zd //不能写 = 函数名() 函数变量名内就存储着函数内容

var x = 0
function zd() {

x++
if (x == img_.length) {
x = 0
}
img.src = img_[x]
// console.log(x)
}
setInterval(zd,1000)//计时器重复操作写函数变量名

setTimeout():在指定的毫秒数后调用函数或计算表达式。在指定的时间之后执行一次

setTimeout(function(){//执行方法
console.log(10)
},3000)//间隔三秒

call()方法

它可以用来调用所有者对象作为参数的方法。

通过 call(),您能够使用属于另一个对象的方法

call ( obj,参数列表 ) call方法传入两个参数,第一个为对象(必写)。若没有对象传入,写法为 call( null , 参数列表 )

var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var person2 = {
firstName:"Steve",
lastName: "Jobs"
}
var x = person.fullName.call(person2); //调用fullName,传入的参数为person2
console.log(x);//Steve Jobs

apply()方法

apply() 方法与 call() 方法非常相似

同样必须传入两个参数 apply ( obj , 参数数组 ) 若只传数组,则写法为:apply ( null , array )

不同之处是: call() 方法分别接受参数。 apply() 方法接受数组形式的参数。 如果要使用数组而不是参数列表,则 apply() 方法非常方便

var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var x = person.fullName.apply(person1);
console.log(x);//Bill Gates




//apply() 方法接受数组中的参数
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var x = person.fullName.apply(person1, ["Seatle", "USA"]); //apply()用数组传递参数
console.log(x);//Bill Gates,Seatle,USA



//call()方法不用数组传递参数
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var person2 = {
firstName:"Steve",
lastName: "Jobs"
}
var x = person.fullName.call(person1, "Seatle", "USA"); //call()不用数组传递参数
console.log(x);//Bill Gates,Seatle,USA

Dom 事件

全称:文档对象模型(Document Object Model,简称DOM )
根元素<html> 上级为文档


通过这个对象模型,JavaScript 获得创建动态 HTML 的所有力量
能改变页面中的所有 HTML 元素
能改变页面中的所有 HTML 属性
能改变页面中的所有 CSS 样式
能删除已有的 HTML 元素和属性
能添加新的 HTML 元素和属性
能对页面中所有已有的 HTML 事件作出反应
能在页面中创建新的 HTML 事件


在 HTML DOM (Document Object Model) 中 , 每一个元素都是 节点
在节点树中,顶端节点被称为根节点
每个节点都有父节点、除了根(它没有父节点)
<html> 节点没有父节点;它是根节点
<head> 和 <body> 的父节点是 <html> 节点
文本节点 "Hello world!" 的父节点是 <p> 节点

Dom 对象 - 方法和属性

DOM 方法 是我们可以在节点(HTML 元素)上执行的动作。
DOM 属性 是我们可以在节点(HTML 元素)设置和修改的值。
属性是您能够获取或设置的值(就比如改变 HTML 元素的内容)。
方法是您能够完成的动作(比如添加或删除 HTML 元素)。

节点(Node)





节点属性是节点(HTML 元素)的值,能够获取或设置
* Node
innerHTML 获取/设置/改变一个元素的标签和开始标签与结束标签之间的内容(所有元素内的内容都会识别,包括子元素标签等)(建议使用)
innerText 也可以获取元素内的内容,但是innerText不识别换行空格等,只识别文本(一般不建议使用)
className 获取/设置一个元素的class属性的属性值
value 获取/设置一个元素的value属性
parentNode 获取一个元素的父级元素
children 获取该元素的子元素集合//元素


事件
本质:Node节点下的方法
onclick 单击事件//(通过更改class name 切换为另一个css样式)
onmouseover 鼠标移上事件
onmouseout 鼠标离开事件
//给伪数组添加事件时必须添加到具体元素,因为伪数组也为对象,添加方法相当于给对象添加了属性(遍历添加)


两种绑定方式
1、<button onclick="displayDate()"> 点我 </button> //将按钮绑定单击事件,单击执行方法
function displayDate(){ //设置单击方法
alert('11')
}

2、document.getElementById("myBtn").onclick=function(){alert(11)}; //获得按钮节点.绑定单击事件 = 方法





//选项卡 方法1:通过JS更改样式 方法2:通过JS更改类名,对应要改变的样式
var head = document.getElementsByClassName('sj')
for (var i = 0; i < head.length; i++) {
/ head[i].number = i///注意赋下标(在排他中用到)

head[i].onclick = function(){
for (var j = 0; j < head.length; j++) {
head[j].style.background = 'blue'//排他思想,点击后所有背景都为蓝色
}
this.style.background = 'red'//this指向调用的这个div,改为红色
}

}//实现选项卡功能,点击哪个哪个变色,点击其他的,之前点击的颜色变回初始颜色

获取节点方法

如何获取我们的节点

document == 网页文档(访问 HTML 页面中的任何元素,那么您总是从访问 document 对象开始)

getElementById() 返回一个与id值相匹配的Node节点

getElementsByClassName() 返回一个与类名相匹配的NodeList(类数组)//注意:返回值为伪数组,获取元素时需要遍历

getElementsByTagName() 返回一个与标签名相匹配的NodeList(类数组)//注意:返回值为伪数组,获取元素时需要遍历

document.querySelector()获取指定选择器元素集合的第一个元素节点//返回一个节点

document.querySelectorAall() 获取指定选择器的所有元素集合//返回节点集合

querySelector与getElement 的区别:前者获取内容的为静态的(获取内容不随着文档变化),后者获取的内容为动态的(随着文档改变内容改变)//但是前者===后者,是因为JS底层逻辑规定的

动态创建获取添加删除节点方法

一般的,节点至少拥有nodeType(节点类型),nodeName(节点明称),和nodeValue(节点值)这三个基本属性

元素节点nodeType为1

属性节点nodeType为2

文本节点nodeType为3,文字,空格,换行等

获取子节点:父节点.childNodes ( 数组形式 )

获取父级节点:子节点.parentNode

获取子节点:节点.childNodes (标准) 一般不使用(兼容性问题)

返回指定节点的子节点的集合,该节点位及时更新的集合(包括注释,文本,元素都会返回)

获取子节点:节点.chlidren (非标准)得到各大浏览器支持 (最常用)

返回节点下所有子元素节点,其他不返回(只返回元素)

获取 第一个 元素 子节点: 节点.firstElementChild (IE9以上浏览器支持)

获取 最后一个 元素 子节点: 节点.lastElementChild (IE9以上浏览器支持)

获取 当前元素节点的下一个兄弟节点: 当前节点.nextElementSibling (没有则返回null)(兼容性IE9以上)

获取 当前元素节点的上一个兄弟节点: 当前节点.previousElementSibling (没有则返回null)(兼容性IE9以上)

动态创建元素节点: document.createElement('tagName') //标签名

(.innerHTML也能创建元素节点 )

通过不同思路使用不同的创捷节点方法(考虑时间优化问题)

var a = document.createElement('div')

动态添加节点

父级节点.appendChild( ' 子节点 ' ) 添加在父节点列表 末尾

var a = document.createElement('div')
a.innerHTML = 'haizi5'
a.className = 'ppp'//添加属性还是用JS原本添加属性的方法
father.appendChild(a)

父节点.insertBefore(子节点) 添加在父节点列表 任意位置 (括号内添加两个参数) ( 添加节点名 , 添加在哪个子元素节点前 )

var father = document.getElementsByClassName('father')[0]//获取父元素
var a = document.createElement('div')//动态创建子元素
a.innerHTML = 'haizi5'
father.insertBefore(a,father.children[2])//将子元素插入在父元素中,插入位置为第3个子元素前

给页面动态添加一个元素话需要3步奏

1.创建一个节点

2.找到父级节点

3.将元素插入父级节点

删除节点:

node.removeChild(节点) 删除选中节点

父节点名.removeChild(要删除的子节点名)
//获取:		//没加Element获取的子节点都包含注释节点等
.childNodes (数组) //获取子元素(所有元素,包括文本节点和注释节点)
.parentNode //获取父元素
.chlidren (数组) //获取子元素(返回数组,只返回标签节点)(常用)
.firstElementChild//获取子元素第一个标签节点
.firstChild //获取第一个节点(包括注释节点)
.lastElementChild//获取最后一个标签节点
.nextElementSibling//获取当前标签节点的下一个兄弟标签节点
.previousElementSibling//获取当前标签节点的上一个兄弟标签节点

TAB 选项卡(三种方法)


// var tab_ = document.getElementsByClassName('div4_2_1')//控制
// var tab = document.getElementsByClassName('tab_')//图片

// for(let i = 0;i<tab_.length;i++){ //let声明方法
// tab_[i].onmouseenter = function(){
// for(var j = 0;j<tab_.length;j++){
// tab[j].style.zIndex = 1;
// tab[j].style.opacity = 0
// tab_[j].className = 'div4_2_1'
// }
// tab[i].style.zIndex = 99 //let声明方法,使i在function内也可以被使用
// tab[i].style.opacity = 1;
// tab_[i].className = 'div4_2_1 bhh'
// }
// }






// for(var i = 0;i<tab.length;i++){
// (function(i){ //闭包方法 设置自调用函数,使i的值传入function
// // console.log(i)
// tab_[i].onmouseenter= function(){
// // console.log(i)
// for(var j = 0;j<tab_.length;j++){
// tab[j].style.zIndex = 1;
// tab[j].style.opacity = 0
// tab_[j].className = 'div4_2_1'
// }
// tab[i].style.zIndex = 99; //i的值被闭包函数传入,不用另外设置下标
// tab[i].style.opacity = 1;
// tab_[i].className = 'div4_2_1 bhh'
// }
// })(i)
// }








// for (var j = 0; j < tab.length; j++) {
// tab_[j].number = j //给图片集合设置序号
// tab_[j].onmouseover = function () { //设置下标方法
// for (var i = 0; i < tab.length; i++) {
// tab[i].style.zIndex = 1
// tab[i].style.opacity = 0
// tab_[i].className = 'div4_2_1'
// }//排他
// tab[this.number].style.zIndex = 99 //根据序号下标改变元素样式,为什么不能用j?因为j的值不能传入事件中,不管是tab[j],还是tab_[j]
// tab[this.number].style.opacity = 1
// this.className = 'div4_2_1 bhh'
// }
// }

自定义属性

定义自定义属性为了与自带属性区分,通常属性前加data- 例:data-num='0'

如何设置自定义属性:

1.直接在标签中设置:例 : <div data-number = '1' > </div>

2.在JS中设置: 例: 节点名.setAttribute ( ' 属性名 ' , 属性值 ) //注意区分对象的添加属性和自定义属性

3.在JS中设置:节点名.dataset.属性名 = 属性值 (这种设置方法为默认在属性名前添加data-)可能存在兼容性问题

用自定义方法设置标签自带的属性名,可以覆盖原本的属性

调用自定义属性:1.节点名.getAttribute( ' 自定义属性名 ' )

2.当自定义属性符合H5命名规范后,可以用 节点名.dataset.自定义属性名(不用加data-)来获取 例: 现有自定义属性 data-index = '5'

调用: 节点名.dataset,index

Dom 总结

创建操作:
1.document.write
2.innerHTML
3.createElement

增加操作:
1.appenChild
2.insertBefore

删除操作
removeChild

修改操作
1.修改元素的属性:src,href,title等
2.修改元素的内容:innerHTML,innerText
3.修改表单元素:value,type,disabled
4.修改样式:style,className

查询操作:
1.dom提供的API方法:getElementById,getElementsByTagName古老用法不太推荐
2.H5提供的新方法:querySelector,querySelectorAll提倡
3.利用节点操作获取元素:父(parentNode),子(child),兄(previousElementSibling),nextElementSibling

自定义属性:
1.setAttribute:设置自定义属性
2.getAttribute:得到dom的属性
3.removeAttitude:移出属性

事件操作:
1.onclick:点击事件
2.ondblclci:双击事件
3.onfocus:鼠标移入事件
4.onblur:鼠标移出事件
5.onmouseover:鼠标移上触发
6.onmouseout:鼠标移出触发

BOM对象

BOM就是浏览器窗口对象模型,顶点对象就是window,Bom包含了Dom

JS执行机制

JS执行机制: 单线程 JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事

同步和异步

为了解决单线程的这个问题,利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创 建多个线程。于是,JS 中出现了同步和异步

同步任务 :同步任务都在主线程上执行,形成一个执行栈 异步任务 :js 的异步任务事通过回调函数实现的。一般而言,异步任务有以下三种类型:

①普通事件:如 click , resize等

② 资源加载:如 load , error 等

③定时器:包括 setInterval , setTimeout等

异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)

执行顺序: ①先执行执行栈中的同步任务 ②异步任务(回调函数)放入任务队列中 ③一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。 ④由于主线程不断的重复获得任务,执行任务,再获取任务,再执行,所以这种机制被称为“事件循环”(event loop)。

 bt.style.display = 'block'			//先设置盒子block
setTimeout(function () { //设置延时器,但是延时时间为0,利用异步,使得Dom加载完再执行延时器
bt.style.opacity = '1' //再设置一个transition:1s; 就有渐显效果
}, 0);

元素偏移量 offset 系列

节点.offsetParent // 返回作为该元素 带有定位 的父级元素,如果父级元素 没有定位则返回body 节点.offsetTop // 返回元素相对 带有定位 父元素上方的偏移 节点.offsetLeft // 返回元素相对 带有定位 父元素左边框的偏移 节点.offsetWidth // 返回自身包括padding 、边框 、内容区的宽度,返回数值不带单位 节点.offsetHeight // 返回自身包括padding 、边框 、内容区的高度,返回数值不带单位

offset 与 style 的区别 offset style offset可以得到任意样式表中的样式值 style只能得到行内样式表中的样式值(通过CSS写的样式获取不到) offset系列获取的数值没有单位 style获取的是带有单位的字符串 offsetWidth包含padding + border + width style.width获得不包含padding和border offsetWidth等属性是只读属性,只能获取不能赋值 style.width可读写 所以,offset用来获取,style用来更改值

元素可视区 client 系列

client 翻译过来就是客户端,我们使用 client 系列的相关属性来获取元素可视区的相关信息。通过 client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等 element.clientTop 返回元素上边框的大小 element.clientLeft 返回元素左边框的大小 element.clientWidth 返回自身包括padding+内容区的宽度、不含边框,返回数值不带单位。 element.clientHeight 返回自身包括padding+内容区的高度、不含边框,返回数值不带单位。

元素滚动 Scroll 系列

使用 scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等 scrollWidth / scrollHeight内容没有超出元素范围时 scrollWidth = 元素宽度 + 内边距宽度 == clientWidth scrollHeight = 元素高度 + 内边距的高度 == clientHeight 内容超出元素范围时 scrollWidth = 元素宽度 + 内边距宽度 + 超出的宽度 scrollHeight = 元素高度 + 内边距的高度 + 超出的高度 scrollTop / scrollLeft scrollTop 超出元素内边距顶部的距离 scrollLeft 超出元素内边距左边的距离

onscroll 事件

滚动条在滚动时会触发 onscroll 事件 浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动时,页面上面被隐藏 掉的高度,我们就称为页面被卷去的头部 页面被卷去的头部:可以通过window.pageYOffset 获得 如果是被卷去的左侧 window.pageXOffset 例:点击按钮回到页面顶端

 document.addEventListener('scroll', function () {			// bt 为回到顶端的按钮   创建scroll 事件
if (window.pageYOffset >= 500) { //如果页面被卷去500 (px)
bt.style.display = 'block' // 显示 bt 按钮
setTimeout(function () {
bt.style.opacity = '1' // 利用异步 使得按钮有渐显效果
}, 0);
}else{
bt.style.opacity = '0' //如果页面没有被卷去500 (px)
setTimeout(function () {
bt.style.display = 'none' //隐藏按钮
}, 0);
}
})
bt.onclick = function(){ //给按钮创建单击事件
var item = setInterval(function(){ //创建计时器 每10ms 滚动距离-50 使得页面有逐渐上滚的效果
if(window.pageYOffset > 0){
var Y = window.pageYOffset
Y -= 50
window.scroll(0,Y) // X轴为0 Y轴实时变化
}else{
clearInterval(item) // 当被卷去距离为0时关闭计时器
}
},10)
}

兼容性问题: DTD: <!DOCTYPE html> (页面头部) 1.声明了 DTD,使用 document.documentElement.scrollTop 2.未声明 DTD,使用 document.body.scrollTop 3.新方法 window.pageYOffset 和 window.pageXOffset,IE9 开始支持

function getScroll() {		//解决兼容性问题
return {
left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft||0,
top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0
};
}
调用时 getScroll()

this 指向问题

在普通函数中 this指向了widow对象

Function xx() {
console.Log(this)
}
xx()调用后的这里的 this 指向 widow

call apply bind Function 对象自带的三个方法,这三个方法的主要作用是改变函数中的 this 指向

call() 方法和 apply() 方法 作用:改变函数的this指向 相同点: 这两个方法的作用是一样的 不同点: 接收参数的方式不同(根据接收参数情况使用两种方法)

call() 方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。

apply() 方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。

bind() 方法 接收的参数与call一样但是调用方式不一样

//方法使用方式:
函数.call(设置指向的对象,参数1,参数2...)//call方法内第一个参数为this的指向方向,后面为函数需要传入的参数(用逗号隔开)
函数.apply(设置指向的对象,[参数1,参数2...])//apply方法第一个参数为this指向的方向,后面函数需要传入的参数以数组的形式写
函数.bind(设置指向的对象,参数1,参数2...)()//

apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;

apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;

apply 、 call 、bind 三者都可以利用后续参数传参;

bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用

bind方法是ES5 新增的一个方法,传参和call方法一致。与call、apply方法的区别是,call和apply方法会对目标函数进行自动执行,会返回一个新的函数。call和apply无法在事件绑定函数中使用。而bind弥补了这个缺陷,在实现改变函数 this 的同时又不会自动执行目标函数,因此可以完美的解决上述问题

节点.cloneNode ( )

// 值为空或false 为浅拷贝 只复制节点本身,不复制节点内的子节点

// 值为true 为深拷贝 复制节点以及节点内的所有子节点

注册事件(绑定事件)

给元素添加 事件 ,称为注册事件或者绑定事件, 注册 事件 有两种方式:传统方式和方法监听注册方式 两种传统绑定事件方式:

1.<div onclick=”index()”></div> ///标签内绑定
function index(){
console.log(1)
}
2.node.onclick=function(){//JS中绑定
console.log(1)
}

传统事件绑定特点:注册事件的唯一性 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前边注册的处理函数

监听 方法注册方式: addEventListener() 特点: 同一个元素同一个事件可以注册多个监听器 按照注册顺序依次执行

传统方式默认只触发冒泡阶段,监听事件可以通过调整参数触发捕获阶段

//写法:
节点名.addEventListener(type,listener,uesCapture)//将监听器注册到目标节点身上,对象触发指定事件时,就会执行处理函数
//该方法的三个参数:
1.type:事件类型;类型字符串,比如click,mouseover,//注意这里没on
2.listener:事件处理函数,事件发生时我们会调用的函数
3.uesCapture:可选参数,是一个布尔值。默认是false,false/true:false为冒泡/ture为捕获,参数是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序//有兼容性问题IE9
//IE9前的事件监听方法:(了解)
//节点.attachEvent(EventNameWithOn,callback)
//EventNameWithOn:事件类型必须加on
//callback:事件处理函数,当目标被触发时执行

删除事件(解除绑定)

删除传统绑定事件: node.onclick = null

删除监听事件的方式: 1. removeEventlistener 节点.removeEventlistener(type,listener,useCapture) (主要) 2.dataEvent 节点.dataEvent(eventNameWithOn,callback) (IE9以下使用)

var btn2=document.getElementById("btn2");/*匿名函数*/
24 btn2.addEventListener("click",function(){//添加事件
25 alert(123);
26 removeEventListener("click",function(){//解除监听事件
27 alert(123)
28 },false)
29 },false)

DOM事件流

事件流描述的是从页面中接收事件的顺序。 事件发生时会在元素节点之间按照特定的顺序传播,这个传播的过程叫做DOM事件流

DOM事件流分为三个阶段,分别为:

捕获阶段:事件从Document节点自上而下向目标节点传播的阶段;

目标阶段:真正的目标节点正在处理事件的阶段;

冒泡阶段:事件从目标节点自下而上向Document节点传播的阶段。

1.也就是你说当我们点击的时候,是从上到下进行监听的,首先接收点击事件,然后查看我们的document有没有绑定事件,没绑定的话继续向下寻找,经过了html,body,再继续向下查找直到找到我们的添加了点击事件的这个元素,这个阶段叫捕获阶段 2.然后找到了点击事件绑定的具体的元素节点(比如具体的某个div)这个阶段叫目标阶段 3.到达目标之后还没有结束,他会继续向上执行,也就是继续向上进行执行我们的点击事件。这个阶段叫冒泡阶段

注意: 1.js代码中只能执行捕获阶段或者冒泡阶段的其中一个阶段 2.onclick和attachEvent只能得到冒泡阶段

事件对象(重点)

event 对象代表事件的状态 也就是在触发的事件的函数里面我们会接收到一个event对象,这个对象有我们需要的一些参数,比如说我们需要知道此事件作用到谁身上了,就可以通过event的属性target来获取到(IE暂且不谈)

Node.onclick = function(event){
//我们把这里的形参叫做事件对象
// 括号内可以设置任意形参代替
}

在这里这个event是个形参,系统自动帮我们设置成为事件对象所以我们就不需要传递实参给它 在我们创建事件的时候系统就会自动帮我们创建这个事件对象,并且呢会依次传递给事件监听器(事件处理函数) IE9以下不识别,IE9以下需要从window.event中获取

事件对象属性方法: e.target //返回触发事件对象 (标准) e.srcElement //返回触发事件对象 (非标准,IE6-8使用) e.type //返回事件类型 比如click mouseover 不带on e.cancleBubble //阻止冒泡 (非标准 IE6-8使用) e.returnValue //阻止默认事件 例如a标签不跳转 (非标准IE6-8使用) e.preventDefault() //阻止默认事件(标准) e.stopPropagation() //阻止冒泡 (标准)

e.target 获取的是事件的触发元素 ,我们的实事件中还存在this这个关键字,两者的区别是,e.target 是点谁触发指向谁,this是谁调用就指向谁

兼容性问题: 在标准情况下浏览器传递的参数,只需要我们定义形参event就可以获取到 在ie9以下需要window.event中获取 兼容性处理就是 e = e || window.event

例:在选项卡中,利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上, ul 有注册事件,就会触发事件监听器,仅操作了一次DOM,提高了程序的性能。

阻止事件冒泡

e.stopPropagation() 正常浏览器可以使用

window.event.cancelBubble= false ie9以下可以使用

//兼容性处理
If(e){
e.stopPropagation()
}else{
window.event.cancelBubble= false
}

事件委托(代理、委托)

不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。只操作了一次 DOM ,提高了程序的性能

例:在选项卡中,利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上, ul 有注册事件,就会触发事件监听器。只操作了一次DOM,提高了程序性能。

常用的鼠标事件

onmousemove \ onmouseenter \ onmouseleave \ ...

oncontextmenu  鼠标右键点击事件
document.oncontextmenu = function(e){ 禁用鼠标右键
return false
}
onselectstart 鼠标选中内容事件
document. onselectstart = function(e){ 禁止选中内容
return false
}
//使用return方法有弊端,return后面的代码不会再被执行

鼠标的事件对象: e.clirntX //返回鼠标相对于浏览器窗口可视区的X坐标 e.clientY //返回鼠标相对于浏览器窗口可视区的Y坐标 e. pageX //返回鼠标相对于文档页的X坐标,IE9+支持(常用) e. pageY // __ e.screenX //返回鼠标相对于电脑屏幕的X坐标 e.screenY // __

常用的键盘事件

键盘事件的对象keycode

onkeyup 按键松开是触发

onkeydown 按键按下时触发

onkeypress 按键被按下并松开是触发

但是这里必须绑定给document文档对象

键盘事件的对象:keycode

 document.onkeydown = function(e){//绑定键盘事件
console.log(e.keyCode)//每点击一个键,找到这个键的keyCode
if(e.keyCode == 13){//如果点击enter键,打印1
console.log(1)
}
}

JS的入口函数

<script type="text/javascript">
window.onload = function(){//JS入口函数
//在这里写JS
}
</script>

JS 封装方法

轮播图插件

Swiper中文网-轮播图幻灯片js插件,H5页面前端开发

//设置鼠标以上分页器切换
//此方法为模拟的,hover到分页器的小圆点后自动触发其本身的click事件
$(".swiper-pagination-bullet").hover(function() {
$(this).click(); //鼠标划上去之后,自动触发点击事件来模仿鼠标划上去的事件
},function() {
mySwiper.autoplay.start(); //鼠标移出之后,自动轮播开启
})



autoplay: true,//自动轮播
autoplay :{//设置轮播属性
delay :0,//自动切换时间间隔 单位ms
disableOnInteraction:false//用户操作swiper后是否禁止autoplay
},

``

//自定义分页器
https://blog.csdn.net/qq_16371909/article/details/78247084

获取随机颜色 #000000

function randomcolor() {
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E']//设置数组,在此选择元素插入arr_
var arr_ = [] //设置颜色数组
for (var i = 0; i < 6; i++) { //设置6位循环
var a = Math.floor(Math.random() * 16) //设置0-16的随机数
arr_.push(arr[a]) //将下标位0-16的arr元素插入arr_中
}
var color = '#' + arr_.join('') //将颜色数组字符串拼接,形成随机颜色
return (color) //返回随机颜色
}

返回一个 a1 到 a2 之间的随机数

function fn(a1, a2) {

var num = Math.floor(Math.random() * (a2 - a1 + 1) + a1)

return(num)
}
//若需要多个,则在其中添加for循环即可
var n = [6,3,5,9,0,5,7,6,1,4,2,3,6,7,8,5,4,3,9,0]

    for(var i = 0 ;i< n.length; i++){
        for(var j = i+1 ; j<n.length; j++){
            if(n[i] == n[j] ){
                n.splice(j,1)
                j--
            }
        }
    }
    console.log(n)          //数组重复数字删除

数组普通排序

 var arr = [5, 7, 9, 6, 3, 4, 2, 1, 8]


function ptpx(arr){
//普通排序

for (var i = 0; i < arr.length - 1; i++) {//j为i+1,省去一次循环步骤
for (var j = i + 1; j < arr.length; j++) {//在内循环中,i始终没变,相当于前面的数与后面每一个比较
if (arr[i] > arr[j]) {//当前下标为i的值与当前下标为j的进行比较,如果大于就准换位置
sun = arr[i]//第三方变量存储值并更换值
arr[i] = arr[j]
arr[j] = sun
}
}
}
return(arr)
}

数组冒泡排序

    var n = [1, 2, 3, 4, 5, 6, 7, 8, 9, 5, 3, 1, 5, 6, 7, 3, 3, 3]

function mppx(n){
for(var i = 0 ; i< n.length-1;i++){//-1是因为大的数已经排在后面了,最前面的数已经是最小的了,不用再排一遍
    for(var j = 0 ;j < n.length-i-1;j++ ){// -i是因为冒泡排序排在后面,后面的顺序已经排完,不用再参与排序;-1是因为if中有+1,在此补上
        if(n[j] > n[j+1]){//比较相邻两数大小,如果后值较大,交换相邻两数位置
            var k = ''
            k = n[j+1]
            n[j+1] = n[j]
            n[j] = k
        }
    }
                        //数组排序
}
return(n)
}
var look = true //在单击事件外
onclick//单击事件
if(!look){ return} //截留锁
look = false //单击后look为 false 在500ms内再次单击后将执行return 不执行后面的代码
setTimeout(function(){ //设置500ms的延时器,点击后过500ms才可以再次点击,500ms内将执行return,不执行后面的代码
look = true
},500)

html:

                    <div class="quantity-input">
<span>数量:</span>
<input type="button" value="+" class="pius ys">
<input type="button" value="1" class="num">
<input type="button" value="-" class="minus ys quantity-u">
</div>
.quantity-input{
float: left;
margin: 10px 10px 0px 0px ;
}
.quantity-input input{
width: 40px;
height: 30px;
margin: 0px;
}
.ys{


}

.quantity-input .num{
width: 50px;
}
$(".pius").click(function () {//数量 + 按钮
var x = $(this).index(".pius")
var num = $(".num").eq(x).val();
num = parseInt(num) + 1;
$(".num").eq(x).val(num);
var oprice = $(".m-money_a").eq(x).text() * num;
$(".sale-money_a").eq(x).html(oprice);
})
$(".minus").click(function () {//数量 - 按钮
var x = $(this).index(".minus")
var num = $(".num").eq(x).val();
num = parseInt(num) - 1;
if (num < 1) {
num = 1;
alert("数量已经为最低")
}
$(".num").eq(x).val(num);
var oprice = $(".m-money_a").eq(x).text() * num;
$(".sale-money_a").eq(x).html(oprice);
})

动态背景线条

将下段js引入至body中

<script type="text/javascript" src="./1.js" opacity= 1></script>
    //立即执行函数
//!的作用是告诉javascript引擎这是一个函数表达式,不是函数声明,()、!、+、-等运算符都能实现这个作用,不过()是最安全的
//在!function(){}后面加上()会立即调用这个函数
//这样做可以模仿一个私有作用域,这样html文件引用多个js文件时便不会造成变量冲突
! function () {
//canvas元素相关
//创建canvas元素,并设置canvas元素的id
var canvas = document.createElement("canvas"),
context = canvas.getContext("2d"),
attr = getAttr();
//设置创建的canvas的相关属性
canvas.id = "c_n" + attr.length;
canvas.style.cssText = "position:fixed;top:0;left:0;z-index:" + attr.z + ";opacity:" + attr.opacity;
//将canvas元素添加到body元素中
document.getElementsByTagName("body")[0].appendChild(canvas);
//该函数设置了canvas元素的width属性和height属性
getWindowWH();
//onresize 事件会在窗口或框架被调整大小时发生
//此处即为当窗口大小改变时,重新获取窗口的宽高和设置canvas元素的宽高
window.onresize = getWindowWH;
//该函数会得到引用了本文件的script元素,
//因为本文件中在赋值时执行了一次getScript函数,html文件引用本文件时,本文件之后的script标签还没有被浏览器解释,
//所以得到的script数组中,引用了本文的script元素在该数组的末尾
//该函数的用意为使开发者能直接修改在html中引入该文件的script元素的属性来修改画布的一些属性,画布的z-index,透明度和小方块数量,颜色
//与前面往body元素添加canvas元素的代码配合,当开发者想要使用该特效作为背景时,只需在html文件中添加script元素并引用本文件即可
function getAttr() {
let scripts = document.getElementsByTagName("script"),
len = scripts.length,
script = scripts[len - 1];//v为最后一个script元素,即引用了本文件的script元素
return {
length: len,
z: script.getAttribute("zIndex") || -1,
opacity: script.getAttribute("opacity") || 1,
color: script.getAttribute("color") || "0,0,0",
count: script.getAttribute("count") || 109
}
}
//获得窗口宽高,并设置canvas元素宽高
function getWindowWH() {
W = canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
H = canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
}
//生成随机位置的小方块
var random = Math.random,
squares = [];//存放小方块
//往squares[]数组放小方块
for(let p = 0; p < attr.count; p ++){
var square_x = random() * W,//横坐标
square_y = random() * H,//纵坐标
square_xa = 2 * random() - 1,//x轴位移 -1,1
square_ya = 2 * random() - 1;//y轴位移
squares.push({
x: square_x,
y: square_y,
xa: square_xa,
ya: square_ya,
max: 6000
})
}
//生成鼠标小方块
var mouse = {
x: null,
y: null,
max: 20000
};
//获取鼠标所在坐标
window.onmousemove = function (i) {
//i为W3C DOM,window.event 为 IE DOM,以实现兼容IE
//不过目前似乎IE已经支持W3C DOM,我用的是IE11,我注释掉下一句代码也能实现鼠标交互效果,
//网上说7/8/9是不支持的,本人没有试验,
//当然加上是没有错的
i = i || window.event;
mouse.x = i.clientX;
mouse.y = i.clientY;
}
//鼠标移出窗口后,消除鼠标小方块
window.onmouseout = function () {
mouse.x = null;
mouse.y = null;
}
//绘制小方块,小方块移动(碰到边界反向移动),小方块受鼠标束缚
var animation = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (i) {
window.setTimeout(i, 1000 / 45)
};//各个浏览器支持的requestAnimationFrame有所不同,兼容各个浏览器
function draw() {
//清除画布
context.clearRect(0, 0, W, H);
var w = [mouse].concat(squares);//连接(合并)鼠标小方块数组和其他小方块数组
var x, v, A, B, z, y;
//square属性表:x,y,xa,ya,max
squares.forEach(function (i) {
//实现小方块定向移动
i.x += i.xa;
i.y += i.ya;
// 控制小方块移动方向
// 当小方块达到窗口边界时,反向移动
i.xa = i.xa * (i.x > W || i.x < 0 ? -1 : 1);
i.ya = i.ya * (i.y > H || i.y < 0 ? -1 : 1);
//fillRect前两个参数为矩形左上角的x,y坐标,后两个分别为宽度和高度
//绘制小方块
context.fillRect(i.x - 0.5, i.y - 0.5, 1, 1);
//遍历w中所有元素
for (let n = 0; n < w.length; n++) {
x = w[n];
//如果x与i不是同一个对象实例且x的xy坐标存在
if (i !== x && null !== x.x && null !== x.y) {
x_diff = i.x - x.x;//i和x的x坐标差
y_diff = i.y - x.y;//i和x的y坐标差
distance = x_diff * x_diff + y_diff * y_diff;//斜边平方
if(distance < x.max){
//使i小方块受鼠标小方块束缚,即如果i小方块与鼠标小方块距离过大,i小方块会被鼠标小方块束缚,
//造成 多个小方块以鼠标为圆心,mouse.max/2为半径绕成一圈
if(x === mouse && distance > x.max/2){
i.x = i.x - 0.03 * x_diff;
i.y = i.y - 0.03 * y_diff;
}
A = (x.max - distance) / x.max;
context.beginPath();
//设置画笔的画线的粗细与两个小方块的距离相关,范围0-0.5,两个小方块距离越远画线越细,达到max时画线消失
context.lineWidth = A * 2;
//设置画笔的画线颜色为s.c即画布颜色,透明度为(A+0.2)即两个小方块距离越远画线越淡
context.strokeStyle = "rgba(" + attr.color + "," + (A + 0.2) + ")";
//设置画笔的笔触为i小方块
context.moveTo(i.x, i.y);
//使画笔的笔触移动到x小方块
context.lineTo(x.x, x.y);
//完成画线的绘制,即绘制连接小方块的线
context.stroke();
}
}
}
//把i小方块从w数组中去掉
//防止两个小方块重复连线
w.splice(w.indexOf(i), 1);
});
//window.requestAnimationFrame与setTimeout相似,形成递归调用,
//不过window.requestAnimationFrame采用系统时间间隔,保持最佳绘制效率,提供了更好地优化,使动画更流畅
//经过浏览器优化,动画更流畅;
//窗口没激活时,动画将停止,省计算资源;
animation(draw);
}
//此处是等待0.1秒后,执行一次draw(),真正的动画效果是用window.requestAnimationFrame实现的
setTimeout(function () {
draw();
}, 100)
}();

动态背景星空

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>HTML5 Canvas全屏背景动画</title>
<style>
body {
background: #060e1b;
overflow: hidden;
}
.codrops-demos {
font-size: 0.8em;
text-align:center;

z-index:99;
width:96%;
}
.codrops-demos a {
display: inline-block;
margin: 0.35em 0.1em;
padding: 0.5em 1.2em;
outline: none;
text-decoration: none;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: 700;
border-radius: 2px;
font-size: 110%;
border: 2px solid transparent;
color:#fff;
}
.codrops-demos a:hover,
.codrops-demos a.current-demo {
border-color: #383a3c;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
"use strict";
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
w = canvas.width = window.innerWidth,
h = canvas.height = window.innerHeight,
hue = 217,
stars = [],
count = 0,
maxStars = 1400;
var canvas2 = document.createElement('canvas'),
ctx2 = canvas2.getContext('2d');
canvas2.width = 100;
canvas2.height = 100;
var half = canvas2.width/2,
gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);
gradient2.addColorStop(0.025, '#fff');
gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)');
gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)');
gradient2.addColorStop(1, 'transparent');
ctx2.fillStyle = gradient2;
ctx2.beginPath();
ctx2.arc(half, half, half, 0, Math.PI * 2);
ctx2.fill();
// End cache
function random(min, max) {
if (arguments.length < 2) {
max = min;
min = 0;
}
if (min > max) {
var hold = max;
max = min;
min = hold;
}
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var Star = function() {
this.orbitRadius = random(w / 2 - 50);
this.radius = random(100, this.orbitRadius) / 10;
this.orbitX = w / 2;
this.orbitY = h / 2;
this.timePassed = random(0, maxStars);
this.speed = random(this.orbitRadius) / 900000;
this.alpha = random(2, 10) / 10;
count++;
stars[count] = this;
}
Star.prototype.draw = function() {
var x = Math.sin(this.timePassed + 1) * this.orbitRadius + this.orbitX,
y = Math.cos(this.timePassed) * this.orbitRadius/2 + this.orbitY,
twinkle = random(10);
if (twinkle === 1 && this.alpha > 0) {
this.alpha -= 0.05;
} else if (twinkle === 2 && this.alpha < 1) {
this.alpha += 0.05;
}
ctx.globalAlpha = this.alpha;
ctx.drawImage(canvas2, x - this.radius / 2, y - this.radius / 2, this.radius, this.radius);
this.timePassed += this.speed;
}
for (var i = 0; i < maxStars; i++) {
new Star();
}
function animation() {
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 0.8;
ctx.fillStyle = 'hsla(' + hue + ', 64%, 6%, 1)';
ctx.fillRect(0, 0, w, h)
ctx.globalCompositeOperation = 'lighter';
for (var i = 1, l = stars.length; i < l; i++) {
stars[i].draw();
};
window.requestAnimationFrame(animation);
}
animation();
</script>
</body>
</html>

鼠标经过爱心

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<title>爱心</title>
<style type="text/css">
body {
margin: 0;
padding: 0;
background: white;
}

#myCanvas {
display: block;
}
</style>
</head>

<body>
<canvas width="400" height="300" id="myLove"></canvas>
</body>
<script type="text/javascript">
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window
.oRequestAnimationFrame ||
window.msRequestAnimationFrame || function (callback) {
window.setTimeout(callback, 1000/ 60);
};
})();
/* *basicstuff */
var FX = {
config: {
background: 'rgba(250,250,250,0.2)',
color: 'rgb(250,0,0)', //初始的颜色
highlight: 'rgb(0,250,0)' //鼠标经过de鼠标经过的颜色
},
dots: []
};
FX.canvas = document.getElementById('myLove');
FX.ctx = FX.canvas.getContext('2d'); /* *Extend Math Object */
Math.TO_RAD = Math.PI / 180;
Math.getDistance = function (x1,
y1, x2, y2) {
var xs = 0,
ys = 0;
xs = x1 - x2;
ys = y1 - y2;
xs = xs * xs;
ys = ys * ys;
return Math.sqrt(xs + ys);
};
Math.getDegree = function (x1, y1, x2, y2) {
var dx = x2 - x1,
dy = y2 - y1;
return Math.atan2(dy, dx) / Math.TO_RAD;
};
/*
*Dot Object */
var Dot = function (opts) {
this.color = opts.color;
this.x = 0;
this.y = 0;
this.dest_x = (opts.dest_x - 75);
this.dest_y = (opts.dest_y - 75);
};
Dot.prototype.update = function () {
var d = this,
dist_x = d.dest_x - d.x,
dist_y = d.dest_y - d.y;
d.x += dist_x * 0.05;
d.y += dist_y * 0.05;
FX.ctx.fillStyle = d.color;
FX.ctx.fillRect(d.x - 2,
d.y - 2, 4, 4);
}; /* *full screen canvas */
FX.setFullscreen = function () {
FX.width = FX.canvas.width = window.innerWidth;
FX.height = FX.canvas.height = window.innerHeight;
}; /* *Mouse */
FX.handleMouseEvent = function (e, power) {
var radius = 75,
k = FX.dots.length,
i = 0,
mx, my, dist, degree, d;
if (e.offsetX) {
mx = e.offsetX;
my = e.offsetY;
} else if (e.layerX) {
mx = e.layerX;
my = e.layerY;
}
mx -= FX.width / 2;
my
-= FX.height / 2;
for (; i < k; i = i + 1) {
d = FX.dots[i];
dist = Math.getDistance(mx, my, d.x, d.y);
if (dist < radius) {
degree = Math.getDegree(d.x, d.y, mx, my);
d.x += (Math.cos(degree * Math.TO_RAD) * ((radius - dist) * power));
d.y += (Math.sin(degree * Math.TO_RAD) * ((radius - dist) * power));
d.color = FX.config.highlight;
} else {
d.color = FX.config.color;
}
}
}; /* *create the heart */
FX.createHeart = function () {
var
coords = [
[1, 4],
[1, 5],
[1, 6],
[1, 7],
[1, 8],
[2, 3],
[2, 4],
[2, 5],
[2, 6],
[2, 7],
[2, 8],
[2, 9],
[3, 2],
[3, 3],
[3, 4],
[3, 5],
[3, 6],
[3, 7],
[3, 8],
[3, 9],
[3, 10],
[4, 2],
[4, 3],
[4, 4],
[4, 5],
[4, 6],
[4, 7],
[4, 8],
[4, 9],
[4, 10],
[4, 11],
[5, 2],
[5, 3],
[5, 4],
[5, 5],
[5, 6],
[5, 7],
[5, 8],
[5, 9],
[5, 10],
[5, 11],
[6, 2],
[6, 3],
[6, 4],
[6, 5],
[6, 6],
[6, 7],
[6, 8],
[6, 9],
[6, 10],
[6, 11],
[6, 12],
[7, 3],
[7, 4],
[7, 5],
[7, 6],
[7, 7],
[7, 8],
[7, 9],
[7, 10],
[7, 11],
[7, 12],
[8, 3],
[8, 4],
[8, 5],
[8, 6],
[8, 7],
[8, 8],
[8, 9],
[8, 10],
[8, 11],
[8, 12],
[8, 13],
[9, 2],
[9, 3],
[9, 4],
[9, 5],
[9, 6],
[9, 7],
[9, 8],
[9, 9],
[9, 10],
[9, 11],
[9, 12],
[10, 2],
[10, 3],
[10, 4],
[10, 5],
[10, 6],
[10, 7],
[10, 8],
[10, 9],
[10, 10],
[10, 11],
[11, 2],
[11, 3],
[11, 4],
[11, 5],
[11, 6],
[11, 7],
[11, 8],
[11, 9],
[11, 10],
[11, 11],
[12, 2],
[12, 3],
[12, 4],
[12, 5],
[12, 6],
[12, 7],
[12, 8],
[12, 9],
[12, 10],
[13, 3],
[13, 4],
[13, 5],
[13, 6],
[13, 7],
[13, 8],
[13, 9],
[14, 4],
[14, 5],
[14, 6],
[14, 7],
[14, 8]
],
k = coords.length,
raster = 10,
i = 0;
for (; i < k; i = i + 1) {
FX.dots.push(new Dot({
dest_x: coords[i][0] * raster,
dest_y: coords[i][1] * raster,
color: FX.config.color
}));
}
}; /* *main loop */
FX.loop = function () {
var ctx = FX.ctx,
k = FX.dots.length,
i = 0;
ctx.fillStyle = FX.config.background;
ctx.fillRect(0, 0, FX.width, FX.height);
ctx.save();
ctx.translate(FX.width / 2, FX.height / 2);
for (; i < k; i = i + 1) {
FX.dots[i].update();
}
ctx.restore();
requestAnimFrame(FX.loop);
}; /* *Event bindings */
window.addEventListener('resize', FX.setFullscreen);
FX.canvas.addEventListener('mousemove', function (e) {
FX.handleMouseEvent(e, -0.1);
});
FX.canvas.addEventListener('mousedown', function (e) {
FX.handleMouseEvent(e, 1);
}); /* *Init */
FX.setFullscreen();
FX.createHeart();
FX.loop();
</script>

</html>

粒子聚合为文字(两行)

将JS 引入进body中

let canvas = document.createElement('canvas');
canvas.style.background = '#000'
document.body.appendChild(canvas);
let gl = canvas.getContext("webgl", {preserveDrawingBuffer: true});

let clearPass = program({
type: gl.TRIANGLES,
vertexSize: 2,
vertices: [-1,3,-1,-1,3,-1], // full screen triangle
shaders: [`
attribute vec2 pt;
void main(void) {
gl_Position=vec4(pt, 0.0, 1.0);
}`, `
void main(void) {
gl_FragColor=vec4(0.0, 0.0, 0.0, 0.05);
}`]
});

let particles = program({
type: gl.POINTS,
vertexSize: 4,
vertices: createVertices(),
uniforms: {time: '1f', resolution: '2f'},
shaders: [`
uniform float time;
uniform vec2 resolution;
attribute vec4 pt;
varying float i;
void main() {
float aspect = resolution.y/resolution.x;
float t = smoothstep(0.0, 1.0, fract(time*0.3));
t += mod(floor(time*0.3), 2.0);
t *= 3.1415;
i = fract(pt.x*pt.y*pt.z*pt.w);
vec2 c = (pt.xy + pt.zw)/2.0;
float a = atan(pt.y - c.y, pt.x - c.x);
float r = length(vec2(pt.x - c.x, pt.y - c.y));
r -= sin(t*3.)*0.005;
c += vec2(cos(a+t), sin(a+t)) * r;
gl_Position = vec4(c.x*aspect, c.y, 0., 1.);
gl_PointSize = 10.0;
}`, `
uniform float time;
varying float i;
float ch(vec2 uv) {
float d = length(uv - 0.5);
return smoothstep(0.2, 0.00, d);
}
void main() {
float d = length(gl_PointCoord.xy-0.5);
d = smoothstep(0.5, 0.00, d);
gl_FragColor = vec4(
ch(gl_PointCoord.xy-0.25*sin(time+i)),
ch(gl_PointCoord.xy),
ch(gl_PointCoord.xy+0.25*sin(time+i)),
0.01
);
}`]
});

gl.enable(gl.BLEND);

requestAnimationFrame(function draw(t) {

gl.blendFunc(gl.ONE, gl.ONE); // additive
particles.bind();
if (canvas.width != innerWidth || canvas.height !== innerHeight) {
particles.uniforms.resolution([innerWidth, innerHeight]);
gl.viewport(0, 0, canvas.width = innerWidth, canvas.height = innerHeight);
}
particles.uniforms.time([t/1000]);
particles.draw();

gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
clearPass.bind();
clearPass.draw();

requestAnimationFrame(draw);

});

function program(o) {
let pid = gl.createProgram();
let bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(o.vertices), gl.STATIC_DRAW);
o.shaders.forEach((src, i) => {
let id = gl.createShader(i?gl.FRAGMENT_SHADER:gl.VERTEX_SHADER);
gl.shaderSource(id, 'precision highp float;\n'+src);
gl.compileShader(id);
var message = gl.getShaderInfoLog(id);
gl.attachShader(pid, id);
if (message.length > 0) {
console.log(src.split('\n').map((str, i) =>
("" + (1 + i)).padStart(4, "0") + ": " + str).join('\n'));
throw message;
}
});
gl.linkProgram(pid);
gl.useProgram(pid);
o.uniforms && Object.keys(o.uniforms).forEach(uf => {
let loc = gl.getUniformLocation(pid, uf),
f = gl[`uniform${o.uniforms[uf]}`];
o.uniforms[uf] = v => f.call(gl, loc, ...v);
});
let pt = gl.getAttribLocation(pid, "pt");
gl.enableVertexAttribArray(pt);
o.draw = () => {
gl.drawArrays(o.type, 0, o.vertices.length/o.vertexSize);
}
o.bind = () => {
gl.useProgram(pid);
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.vertexAttribPointer(pt, o.vertexSize, gl.FLOAT, false, 0, 0);
}
return o;
}

function createVertices() {
let count = 2000;
let vertices = [];
let s = 500;
let canvas = document.createElement('canvas');
canvas.width = canvas.height = s;
let ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, s, s);
ctx.font = `bold ${s/5}px Arial`;
ctx.fillStyle = "red";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
let mask = ["11234", "66789"].map(text => {
ctx.clearRect(0, 0, s, s);
ctx.fillText(text, s/2, s/2);
let data = ctx.getImageData(0, 0, s, s);
return (x, y) => data.data[((y|0)*s+(x|0))*4];
});
while (vertices.length < count*4) {
let x1 = s*Math.random();
let y1 = s*Math.random();
if (!mask[0](x1, y1))
continue
let x2 = s*Math.random();
let y2 = s*Math.random();
if (!mask[1](x2, y2))
continue
let r = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))/2;
if (r>s/6)
continue
vertices.push(2*(x2/s-0.5), 2*(0.5-y2/s), 2*(x1/s-0.5), 2*(0.5-y1/s));
}
return vertices;
}

引入css

body {
margin: 0;
overflow: hidden;
}

a {
position: fixed;
display: inline-block;
margin-left: calc(50vw - 70px);
font-size:20px;
z-index:1;
color: white;
}

网状动态线条

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Delaunay Wave Animation</title>
<style>
body,
html {
margin: 0;
}
canvas {
display: block;
cursor: pointer;
}
</style>
</head>

<body>

<canvas id="canvas" title="单击以生成新图案"></canvas>

<script src='js/JjPbdKp.js'></script>
<script src="js/script.js"></script>

</body>

</html>

script.js

/*
Johan Karlsson, 2021
https://twitter.com/DonKarlssonSan
MIT License, see Details View

https://en.wikipedia.org/wiki/Delaunay_triangulation

https://en.wikipedia.org/wiki/Bowyer%E2%80%93Watson_algorithm

https://en.wikipedia.org/wiki/Circumscribed_circle
*/

class Triangle {
constructor(a, b, c) {
this.a = a;
this.b = b;
this.c = c;
}

vertexes() {
return [this.a, this.b, this.c];
}

edges() {
return [
[this.a, this.b],
[this.b, this.c],
[this.c, this.a]];

}

sharesAVertexWith(triangle) {
// TODO: optimize me please!
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let v = this.vertexes()[i];
let vv = triangle.vertexes()[j];
if (v.equals(vv)) {
return true;
}
}
}
return false;
}

hasEdge(edge) {
for (let i = 0; i < 3; i++) {
let e = this.edges()[i];
if (e[0].equals(edge[0]) && e[1].equals(edge[1]) ||
e[1].equals(edge[0]) && e[0].equals(edge[1])) {
return true;
}
}
return false;
}

get circumcenter() {
if (!this._circumcenter) {
let d = 2 * (this.a.x * (this.b.y - this.c.y) +
this.b.x * (this.c.y - this.a.y) +
this.c.x * (this.a.y - this.b.y));

let x = 1 / d * ((this.a.x * this.a.x + this.a.y * this.a.y) * (this.b.y - this.c.y) +
(this.b.x * this.b.x + this.b.y * this.b.y) * (this.c.y - this.a.y) +
(this.c.x * this.c.x + this.c.y * this.c.y) * (this.a.y - this.b.y));

let y = 1 / d * ((this.a.x * this.a.x + this.a.y * this.a.y) * (this.c.x - this.b.x) +
(this.b.x * this.b.x + this.b.y * this.b.y) * (this.a.x - this.c.x) +
(this.c.x * this.c.x + this.c.y * this.c.y) * (this.b.x - this.a.x));
this._circumcenter = new Vector(x, y);
}

return this._circumcenter;

}

get centroid() {
if (!this._centroid) {
this._centroid = this.a.add(this.b).add(this.c).div(3);
}
return this._centroid;
}

get circumradius() {
if (!this._circumradius) {
this._circumradius = this.circumcenter().sub(this.a).getLength();
}
return this._circumradius;
}

pointIsInsideCircumcircle(point) {
let circumradius = this.circumcenter.sub(this.a).getLength();

let dist = point.sub(this.circumcenter).getLength();

return dist < circumradius;
}

draw(now) {
let phaseOffset = this.centroid.sub(center).getLength() / w * 2;
let m = (Math.sin(now / 1800 + phaseOffset) + 1) * 0.48;
let a = this.a.lerp(this.centroid, m);
let b = this.b.lerp(this.centroid, m);
let c = this.c.lerp(this.centroid, m);

ctx.beginPath();

ctx.lineTo(a.x, a.y);
ctx.lineTo(b.x, b.y);
ctx.lineTo(c.x, c.y);
ctx.closePath();
ctx.fill();
ctx.stroke();
}}


let canvas;
let ctx;
let w, h;
let triangles;
let center;

function setup() {
canvas = document.querySelector("#canvas");
ctx = canvas.getContext("2d");
window.addEventListener("resize", () => {
reset();
setupTriangles();
});
canvas.addEventListener("click", setupTriangles);
reset();
setupTriangles();
}

function setupTriangles() {
let superTriangle = new Triangle(
new Vector(-w * 10, h * 10),
new Vector(w * 10, h * 10),
new Vector(w / 2, -h * 10));


let pointList = getRandomPoints();
triangles = bowyerWatson(superTriangle, pointList);
}

function reset() {
w = canvas.width = window.innerWidth;
h = canvas.height = window.innerHeight;
//ctx.lineCap = "round";
//ctx.lineJoin = "round";
center = new Vector(w / 2, h / 2);
}

function getRandomPoints() {
let extra = 50;

let pointList = [
new Vector(-extra, -extra),
new Vector(-extra, h + extra),
new Vector(w + extra, -extra),
new Vector(w + extra, h + extra)];


let delimiter = Math.random() * 5000 + 300;
let nrOfPoints = w * h / delimiter;
for (let i = 0; i < nrOfPoints; i++) {
pointList.push(new Vector(
Math.random() * (w + extra * 2) - extra,
Math.random() * (h + extra * 2) - extra));

}
return pointList;
}

function bowyerWatson(superTriangle, pointList) {
// pointList is a set of coordinates defining the
// points to be triangulated
let triangulation = [];

// add super-triangle to triangulation
// must be large enough to completely contain all
// the points in pointList
triangulation.push(superTriangle);

// add all the points one at a time to the triangulation
pointList.forEach(point => {
let badTriangles = [];

// first find all the triangles that are no
// longer valid due to the insertion
triangulation.forEach(triangle => {
if (triangle.pointIsInsideCircumcircle(point)) {
badTriangles.push(triangle);
}
});
let polygon = [];

// find the boundary of the polygonal hole
badTriangles.forEach(triangle => {
triangle.edges().forEach(edge => {
let edgeIsShared = false;
badTriangles.forEach(otherTriangle => {
if (triangle !== otherTriangle && otherTriangle.hasEdge(edge)) {
edgeIsShared = true;
}
});
if (!edgeIsShared) {
//edge is not shared by any other
// triangles in badTriangles
polygon.push(edge);
}
});
});

// remove them from the data structure
badTriangles.forEach(triangle => {
let index = triangulation.indexOf(triangle);
if (index > -1) {
triangulation.splice(index, 1);
}
});

// re-triangulate the polygonal hole
polygon.forEach(edge => {
//form a triangle from edge to point
let newTri = new Triangle(edge[0], edge[1], point);
triangulation.push(newTri);
});
});

// done inserting points, now clean up
let i = triangulation.length;
while (i--) {
let triangle = triangulation[i];
if (triangle.sharesAVertexWith(superTriangle)) {
//remove triangle from triangulation
let index = triangulation.indexOf(triangle);
if (index > -1) {
triangulation.splice(index, 1);
}
}
}

return triangulation;
}

function draw(now) {
requestAnimationFrame(draw);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, w, h);

ctx.strokeStyle = "white";
ctx.fillStyle = "white";
ctx.lineWidth = 2;
triangles.forEach(t => t.draw(now));
}

setup();
draw(performance.now());

JjPbdKp.js

/*
Johan Karlsson
https://github.com/DonKarlssonSan/vectory
*/

"use strict";

class Vector {
constructor(x, y) {
this.x = x;
this.y = y;
}

add(v) {
return new Vector(
this.x + v.x,
this.y + v.y);
}

addTo(v) {
this.x += v.x;
this.y += v.y;
}

sub(v) {
return new Vector(
this.x - v.x,
this.y - v.y);
}

subFrom(v) {
this.x -= v.x;
this.y -= v.y;
}

mult(n) {
return new Vector(this.x * n, this.y * n);
}

multTo(n) {
this.x *= n;
this.y *= n;
return this;
}

div(n) {
return new Vector(this.x / n, this.y / n);
}

setAngle(angle) {
var length = this.getLength();
this.x = Math.cos(angle) * length;
this.y = Math.sin(angle) * length;
}

setLength(length) {
var angle = this.getAngle();
this.x = Math.cos(angle) * length;
this.y = Math.sin(angle) * length;
return this;
}

getAngle() {
return Math.atan2(this.y, this.x);
}

getLength() {
return Math.hypot(this.x, this.y);
}

getLengthSq() {
return this.x * this.x + this.y * this.y;
}

distanceTo(v) {
return this.sub(v).getLength();
}

copy() {
return new Vector(this.x, this.y);
}

equals(v) {
return this.x == v.x && this.y == v.y;
}

rotate(angle) {
return new Vector(this.x * Math.cos(angle) - this.y * Math.sin(angle), this.x * Math.sin(angle) + this.y * Math.cos(angle));
}

lerp(v, t) {
let delta = v.sub(this).mult(t);
return this.add(delta);
}

lerpTo(v, t) {
let delta = v.sub(this).mult(t);
this.addTo(delta);
}

moveTowards(v, length) {
let delta = v.sub(this).setLength(length);
return this.add(delta);
}

toString() {
return `${this.x},${this.y}`;
}
}
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Isometric Light Switch</title>

<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="css/style.css">

</head>
<body>

<div class="switch">
<input id="on" type="radio" name="status" value="on"/>
<label for="on">on</label>
<input id="off" type="radio" name="status" value="off" checked="checked"/>
<label for="off">off</label>
</div>

<script src="js/script.js"></script>

</body>
</html>
document.querySelectorAll('.switch input').forEach(radio => {
radio.addEventListener('change', () => {
document.body.dataset.switch = radio.value;
})
})
@import url('https://fonts.googleapis.com/css2?family=Antonio&display=swap');

html, body {
height: 100%;
}

body {
--h: 0;
--s: 0%;
--l: 25%;
--bg: hsl(var(--h), var(--s), var(--l));

--size: 20vmin;
--z: 0;
--dur: 250ms;
--ease: cubic-bezier(0.22, 1, 0.36, 1);

display: grid;
overflow: hidden;
perspective: 50em;
font-family: 'Antonio', sans-serif;
text-transform: uppercase;

transition: background-color var(--dur) var(--ease);
}

[data-switch="on"] {
--h: 205;
--s: 80%;
--l: 100%;
}


.switch {
margin: auto;
display: grid;
place-items: center;
grid-template-rows: 1fr auto auto 1fr;
transform-style: preserve-3d;
transform: scale(0);
animation: animate-in 1600ms 400ms var(--ease) forwards;
}

@keyframes animate-in {
from {
transform: rotateX(0) rotateZ(0) scale(0);
}
to {
transform: rotateX(45deg) rotateZ(45deg) scale(1);
}
}

.switch::before {
content: '';
position: relative;
grid-column: 1 / -1;
grid-row: 1 / -1;
pointer-events: none;
width: calc(var(--size) * 2);
height: calc(var(--size) * 3);

transform: translateZ(-1px);
transition: background-color var(--dur) var(--ease);
}

.switch input {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}

.switch label {
--focus-border: 2px dashed dodgerblue;
--focus-offset: -1vmin;

grid-column: 1;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
cursor: pointer;
font-size: calc(var(--size) / 3);
line-height: 1;
text-shadow: hsla(0, 0%, 0%, 0.05) 2px 2px 0.2vmin;
color: hsl(var(--h) var(--s) calc(var(--l) - 50%));
width: var(--size);
height: var(--size);

transform-style: preserve-3d;
transition: var(--dur) var(--ease);
transition-property: background-color, color, transform;
}

.switch input:focus + label {
outline: var(--focus-border);
outline-offset: var(--focus-offset);
}

.switch input:focus:not(:focus-visible) + label {
outline: none;
}

.switch input:focus-visible + label {
outline: var(--focus-border);
outline-offset: var(--focus-offset);
}

.switch label::before,
.switch label::after {
position: absolute;
right: 0;
pointer-events: none;
transition: background-color var(--dur) var(--ease);
}

.switch label::before {
bottom: 0;
}

.switch input:checked + label {
cursor: initial;

}

.switch label:first-of-type {
grid-row: 2;
transform-origin: center bottom;
transform: rotateX(-25deg);
}

.switch label:last-of-type {
grid-row: 3;
transform-origin: center top;
transform: rotateX(25deg);
}

.switch input:checked + label {
transform: rotateX(0);
}

.switch label::before,
.switch label::after {
content: "";
display: block;
width: 100%;
height: 100%;
}

.switch label::before {
height: calc(var(--size) / 2);

}

.switch label::after {
width: calc(var(--size) / 2);
transform-origin: center right;

}

.switch label:first-of-type::before {
transform-origin: top center;
transform: rotateX(-65deg);
}

.switch label:last-of-type::before {
transform-origin: bottom center;
transform: rotateX(65deg);
}

.switch label:first-of-type::after {
transform: rotateY(-90deg) skewY(-25deg);
}

.switch label:last-of-type::after {
transform-origin: center right;
transform: rotateY(-90deg) skewY(25deg);
}

js原生录屏

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title>wgchen</title>
<link rel="shortcut icon" href="#" />
</head>

<body>

<video class="video" width="600px" controls></video>
<button class="record-btn">record</button>

<script>

let btn = document.querySelector(".record-btn")

btn.addEventListener("click", async function () {
let stream = await navigator.mediaDevices.getDisplayMedia({
video: true
})

// 需要更好的浏览器支持
const mime = MediaRecorder.isTypeSupported("video/webm; codecs=vp9")
? "video/webm; codecs=vp9"
: "video/webm"
let mediaRecorder = new MediaRecorder(stream, {
mimeType: mime
})

let chunks = []
mediaRecorder.addEventListener('dataavailable', function (e) {
chunks.push(e.data)
})

mediaRecorder.addEventListener('stop', function () {
let blob = new Blob(chunks, {
type: chunks[0].type
})
let url = URL.createObjectURL(blob)

let video = document.querySelector("video")
video.src = url

let a = document.createElement('a')
a.href = url
a.download = 'video.webm'
a.click()
})

// 必须手动启动
mediaRecorder.start()
})


</script>

</body>

</html>

移动端JS

移动端浏览器兼容性较好,不需要考虑以前 JS 的兼容性问题,可以放心的使用原生 JS 书写效果,但是移动 端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android 和 IOS 都有。 touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是多跟手指。触屏事件可响应用户手指(或触控 笔)对屏幕或者触控板操作。 触摸事件 touchstart:手指触摸到屏幕会触发 touchmove:当手指在屏幕上移动时,会触发 touchend:当手指离开屏幕时,会触发

触摸事件对象(TouchEvent) TouchEvent 是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多 个触点,使开发者可以检测触点的移动,触点的增加和减少,等等 e.touches 正在触摸屏幕的所有手指的列表 e.targetTouches 正在触摸当前dom元素的手指列表 e.changedTouches 原来有现在没有或者原来没有现在有的手指列表当我们手指离开屏幕时,就没有了 touches和targetTouches列表但是会有changedTouches因为我们一半都是触摸元素,所以最经常使用的时targetTouches

移动端常见的开发插件: iScroll( https://github.com/cubiq/iscroll Swiper( https://www.swiper.com.cn/ SuperSlider( http://www.superslide2.com/ 移动端视频插件zy.media.js (H5提供了video标签,但是浏览器支持情况不同)其他视频插件还有腾讯云、保利威视 等(按流量计费)

移动端常用开发框架

前端常用的框架有 Bootstrap 前端三大框架 Angular、react、vue 他们非一个级别。Vue是框架,bootstrap是基于jQuery的组建库 只是统称为框架

MUI 原生UI前端框架 MUI 是一个专门用于做手机 APP 的前端框架。 http://dev.dcloud.net.cn/mui/

//bootstrap制作五列时的方法:12栅格底层原理是利用媒体查询
//在css中加入此媒体查询
<style>
@media(min-width:1200px){
.col-zdlg-2-5{
float:left;
width:20%;
}
}
</style>
//在使用时使用.col-zdlg-2-5 类名控制即可

click 延时解决方案

移动端 click 事件会有 300ms 的延时,原因是移动端屏幕默认双击会缩放(double tap to zoom) 页面 1.禁用缩放。 浏览器禁用默认的双击缩放行为并且去掉 300ms 的点击延迟

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

\2. 使用插件。 fastclick 插件解决 300ms 延迟。

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

// 等页面文档加载完成 不需要等所有的资源 //

FastClick.attach(document.body);

本地存储特性 : 1、数据存储在用户浏览器中 2、设置、读取方便、甚至页面刷新不丢失数据 3、容量较大,sessionStorage约5M 、localStorage约20M 4、只能存储字符串,可以将对象JSON.stringify() 编码后存储

window.sessionStorage 1.生命周期为关闭浏览器窗口 2.在同一个页面下可以共享数据 3.以键值对的形式进行存储 sessionStorage.setItem( ' key ' , value) 存数据 // 键值均为字符串 sessionStorage.getItem( ' key ' ) 取数据 sessionStorage.removeItem( ' key ' ) 删除单独的 sessionStorage.clear ( ) 删除所有的

window.localStorage 1.生命周期为永久生效,除非手动删除,否则关闭页面也会存在 2.可以多页面共享 (同一浏览器可以共享) 3.以键值对的形式存储数据 localStorage.setItem( ' key ' , value)存数据 localStorage.getItem( ' key ' )取数据 localStorage.removeItem( ' key ' )删除单独的 localStorage.clear ( ) 删除所有的

JSON.stringify( data ) //将对象编码为字符串,方可存入缓存
JSON.parse( )//从缓存中获取字符串对象,用此方法转换为正常对象使用
// parseInt() 函数解析字符串并返回整数。JQ方法
sessionStorage.setItem( ' key ' , value) 存数据//key为缓存中的名字,注意要用字符串
    localStorage.clear();

将对象转换为字符串:

var data = {				//设置一个对象
name:11,
passowrd:123
}
var a = JSON.stringify(data) //将对象转换为字符串
console.log(a) // 转换为字符串后可以储存到本地缓存中
var b = JSON.parse(a) // 将字符串转回对象
console.log(b) // 从本地缓存中读取后,使用此方法变回对象

cookie session 的区别

1.存储位置不同 cookie的数据信息存放在客户浏览器上 session的数据信息放在服务器上 2.存储容量不同 单个cookie保存的数据<= 4kb,一个站点最多保存20个Cookie 对于session来说并没有上限,但是对于服务器的性能考虑,session内不要存放过多的东西,并且设置session的删除机制 3.存储方式的不同 cookie中只能保管ASCII字符串,并需要通过编码方式存储为Unicode字符或者二进制数据 session中能够存储任何类型的数据 4.隐私策略不同 cookie对客户端是可见的,所以他是不安全的 session存储在服务器上,客户端是透明的,不存在敏感信息泄露的风险 5.有效期上不同 开发可以通过设置cookie的属性,达到使cookie长期有效的效果 session依赖于名为JSESSIONID的cookie,而cookie JSESSIONID的过期时间默认为-1,只需关闭窗口该session就会失效,因而session不能达到长期有效的效果 6.服务器压力不同 cookie保管在客户端,不占用服务器资源。对于并发用户十分多的网站,cookie是很好的选择 session是保管在服务器端的,每个用户都会产生一个session。假如并发访问的用户十分多,会产生十分多的session,耗费大量的内存 7.浏览器支持不同

假如客户端浏览器不支持cookie cookie是需要客户端浏览器支持的,假如客户端禁用了cookie,或者不支持cookie,则会话跟踪会失效。关于WAP上的应用,常规的cookie就派不上用场了 运用session需要使用URL地址重写的方式。一切用到session程序的URL都要进行URL地址重写,否则session会话跟踪还会失效

假如客户端支持cookie cookie既能够设为本浏览器窗口以及子窗口内有效,也能够设为一切窗口内有效 session只能在本窗口以及子窗口内有效

8.跨域支持不同 cookie支持跨域名访问 session不支持跨域名访问

JSON.parse()//将从缓存中获取的字符串对象转为正常对象
JSON.stringify()//将对象转换为字符串

页面间传参方式

第一种:利用缓存传参(如上) 第二种:利用a标签跳转传参

<a href="./2.html ?name=李硕&age=22&sex=男">点击跳转到页面2</a>(页面1的a)

var str = location.search;(页面2的接收)
console.log(str) (接收?后的所有内容)//因为传值有中文,所以中文部分为乱码

<script>//后代码均为页面2
var str = location.search;//获取传的值(带?)
str = decodeURI(str);//传的值有中文时进行转码
var arr = str.split("?");//截取 ? 间的内容为一个数组
var arr2 = arr[1].split("&");//截取 & 间的内容为一个数组
console.log(str)
console.log(arr)
console.log(arr2)
var data={};//创建一个对象
$.each(arr2, function(index,item) {//遍历arr2数组
var k = item.split("=")[0];//对象的键为截取 = 前的内容
var v = item.split("=")[1];//对象的值为截取 = 后的内容
data[k] = v;//以键值对的形式给对象插入属性
});
console.log(data)
</script>

JQuery

JQuery对象的本质:利用$对DOM对象包装后产生的对象

两个对象的相互转化: jQuery对象转换为DOM对象 1 $( ‘ span ’ ) [0]下标的方式 2 $( ‘ span ’ ) get ( index ) 索引的方式

$(function(){
$('.cont').click(function(){
console.log(this)//this指向DOM对象而不是JQuery对象
})
console.log($('#cont')[0])//JQuery对象转换为DOM对象
})

JQuery 入口函数

入口函数第一种 $(function(){ // ...此处是页面DOM加载完成的入口 })

入口函数第二种 $( document).ready(function(){ // ...此处是页面DOM加载完成的入口 })

这里的“$”可以换成jQuery 等待DOM结构渲染完毕即可执行内部代码,不用等待所有外部资源加载完成,jQuery帮我们完成了封装 相当于DOMContentLoaded 不同于原声的load事件是等页面文档,外部的js文件,css文件,图片加载完毕才执行内部代码 更推荐使用第一种方式

JQuery入口函数 JS入口函数的区别 1.JavaScript的入口函数比jQuery的入口函数早一些

JavaScript的入口函数要等到 页面中所有资源(包括图片、文件) 加载完成才开始执行。

jQuery的入口函数只会等待 文档树 加载完成就开始执行,并不会等待图片、文件的加载。

2.jQuery的入口函数不会覆盖原有的入口函数,而会进行添加 javascript的入口函数执行的比jQuery的晚,且会进行覆盖 3.jQuery执行较早的好处 例如淘宝,京东这类大网站,图片等资源较多,若要等待全部加载就会导致代码执行很缓慢,因此文档树加载完成再执行代码执行会比较快些

JQ选择器

id选择器 $(‘#id’) 获取指定id元素 //此处全部与css选择器相同 class选择器 $(‘.calss’) 匹配指定类名的所有元素 标签选择器 $(‘div’) 获取标签名为div的同一类元素 全选选择器 $(‘ * ’) 匹配所有元素 并集选择器 $(‘div,li,span’)选取多个元素 交集选择器 $(‘li.current’) 交集元素 子代选择器$(‘ul>li’)子集选择器 后代选择器 $(‘ul li’) 后代选择器

寻找父元素 parent() // 返回被选元素的 直接 父元素 parents() // 返回被选元素的 所有祖先 元素,它一路向上直到文档的根元素( <heml> parentsUntil() // 返回介于两元素之间的所有祖先元素

$(document).ready(function(){
$("span").parentsUntil("div");//返回介于 <span> 与 <div> 元素之间的所有祖先元素
});

寻找子元素 children() // 返回被选元素的所有 直接 子元素 find() // 返回被选元素的后代元素,一路向下直到最后一个后代

  $("div").children("p");//返回所有 <p> 元素,并且它们是 <div> 的直接子元素

$("div").find("span");//返回属于 <div> 后代的所有 <span> 元素

$("div").find("*");//返回 <div> 的所有后代

寻找同胞 siblings ( ) // 返回被选元素的所有同胞元素(可选参数来过滤同胞,不包含自己) next ( ) // 返回下一个同胞元素(该方法只返回一个参数) nextAll ( ) // 返回被选元素的所有跟随的同胞元素 nextUntil ( ) // 返回介于两个给定参数之间的所有跟随的同胞元素 prev ( ) prevAll ( ) prevUntil ( ) // 以上三个方法的工作方式与上面的方法类似,只不过方向相反而已:它们返回的是前面的同胞元素

过滤 first ( ) // 返回被选元素的首个元素 last ( ) // 返回被选元素的最后一个元素 eq ( ) // 返回被选元素中带有指定索引号的元素 find( ) // 返回

filter ( ) // 方法允许您规定一个标准。不匹配这个标准的元素会被从集合中删除,匹配的元素会被返回 not ( ) // 返回不匹配标准的所有元素 odd ( ) // 返回奇数项元素 even ( ) // 返回偶数元素

$("div p").first().css("background-color","yellow");//返回首个 div 标签中 p 标签
$("p").eq(1).css("background-color","yellow");//返回p标签的第二个(index == 1)
$("p").filter(".url").css("background-color","yellow");//返回 p 标签中类名为 url 的所有元素
$("p").not(".url").css("background-color","yellow");//返回不带有类名 "url" 的所有 <p> 元素

JQ设置css样式

//方法一   设置单个css样式
$('div').css('属性名','属性值')
//方法二 设置多个css样式
$('div').css({ //css括号内为一个对象
'属性名':'属性值',
'属性名':'属性值',
})

参数只写属性名,则是返回属性值

$(this).css(''color'');

JQ操作类

添加类 $(“div”) .addClass (''current''); 移除类 $(“div”) .removeClass (''current''); 切换类 $(“div”) .toggleClass (''current''); 检查类$(“div”) .hasClass (''current'');//检查是否含有类名current 返回值为布尔

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

JQ效果方法

显示隐藏 show() // 显示 hide ( ) // 隐藏 toggle ( ) // 切换

hide([speed],[easing],[fn])	// 参数可以全部省略 无动画直接显示
//speed 三种速度预设值 "slow" "normal" "fast" 也可以直接写毫秒 1000
//easing 用来指定切换效果 默认"swing" 可用 "linear"
// fn 回调函数 动画结束时执行
toggle([speed],[easing],[fn]) // 参数可以全部省略,无动画显示

滑动 slideDown ( ) // 下滑 slideUp ( ) // 上滑 slideToggle ( ) // 切换

slideToggle([speed],[easing],[fn])	// 参数可以全部省略 无动画直接显示
//speed 三种速度预设值 "slow" "normal" "fast" 也可以直接写毫秒 1000
//easing (Optional) 用来指定切换效果 默认"swing" 可用 "linear"
// fn 回调函数 动画结束时执行

淡入淡出 fadeIn ( ) // 淡入 fadeOut ( ) // 淡出 fadeToggle ( ) // 切换 fadeTo ( ) // 可设置透明度 ( 1000, .5 )

动画 animate ( )

animate(css,[speed],[easing],[fn])
// css: 想要更改的样式属性,以对象形式传递,必须写。 属性名可以不用带引号, 如果是复合属性则需要采取驼峰命名法 borderLeft。其余参数都可以省略
{height:’500px’,fontSize:’30px’}//css写法(px可以省略)
// speed:三种预定速度之一的字符串(“slow”,“normal”, or “fast”)或表示动画时长的毫秒数值(如:1000)
// easing:(Optional) 用来指定切换效果,默认是“swing”,可用参数“linear”
// fn 回调函数

JQ 遍历

each() 方法规定为每个匹配元素规定运行的函数 $( selector ) .each ( function ( index , element ) ) function(index,element) : index 为下标 e 为事件对象(也可以用" this " 选择器)

返回 false 可用于及早停止循环

stop()

stop() 方法用于在动画或效果完成前对它们进行停止 .stop() "停止" 会停止当前活动的动画,但允许已排队的动画向前执行 .stop(true) "停止所有" 停止当前活动的动画,并清空动画队列;因此元素上的所有动画都会停止 .stop(true,true) "停止但要完成" 会立即完成当前活动的动画,然后停下来

Callback 函数(回调函数)

在动画后可添加回调函数,在动画运行完成后可执行回调函数

$("button").click(function(){
$("p").hide(1000,function(){//回调函数,在动画结束后运行
alert("The paragraph is now hidden");
});
});

.hover ( ) 事件切换

hover( function(){} , function(){} ) 第一个函数为鼠标移上触发的函数(相当于mouseenter) 第二个函数为鼠标移出触发的函数(相当于mouseleave) 如果只写一个函数,则鼠标经过和离开都会触发

.hover ( ) 方法相当于鼠标移入与鼠标移出事件的合体

JQ属性操作(prop attr)

设置或获取元素固有属性 prop ( ) // 只能操作自带属性 设置或获取元素自定义属性 attr ( ) // 可以操作自带属性和自定义属性 移除属性 removeProp ( )

$(selector).attr({attribute:value, attribute:value ...})//设置多个属性注意引号
$(selector).attr(attribute)//返回该属性的属性值
.removeProp("color");//移除color属性

prop() 方法设置或返回被选元素的属性和值。 当该方法用于 返回 属性值时,则返回第一个匹配元素的值。 当该方法用于 设置 属性值时,则为匹配元素集合设置一个或多个属性/值对。 注意: prop() 方法应该用于检索属性值,例如 DOM 属性(如 selectedIndex, tagName, nodeName, nodeType, ownerDocument, defaultChecked, 和 defaultSelected)。 提示: 如需检索 HTML 属性,请使用 attr() 方法代替。

//回调函数
$("#w3s").attr("href", function(i,origValue){
return origValue + "/jquery"; //设置回调函数,返回值为要修改的属性值
});

数据缓存 .data ( )

data() 方法可以在指定的元素上存取数据,并不会修改 DOM 元素结构。一旦页面刷新,之前存放的数据都将被移除 用于设置获取自定义属性

.data ( ' name ' ) // 返回name 属性值 .data ( ' name ' , ' value ' ) // 给被选元素添加name 属性 值为value(附加数据) .data ( ) // 以对象的方式返回所有存储的属性与属性值

只能读取HTML5自定义属性 data-index,得到的是数字型

针对元素的内容的值操作 普通元素内容 .html() (相当于原生.innderHtml ) .html ( ) // 获取元素的内容 .html ( "内容" ) // 设置元素的内容 普通文本元素内容 .text() (相当于原生 .innerText ) .text ( ) // 获取元素的文本内容 .text ( "文本内容" ) // 设置元素的文本内容

针对表单值得操作 表单的值 val ( ) (相当于原生.value) .val ( ) // 获取表单的值 .val ( "内容" ) // 设置表单的值

//text的回调函数
$("#test1").text(function (i, origText) {//i为index,origText为原来的文本
return "Old text: " + origText + " New text: Hello world! (index: " + i + ")";//return返回的内容为要更改的内容 .text("内容")
});

.change ( ) 事件

当元素的值发生改变时,会发生change事件 该事件仅适用于表单元素 change() 函数触发 change 事件,或规定当发生 change 事件时运行的函数

//change()
$(".field").change(function(){
$(this).css("background-color","#FFFFCC");
});

each()遍历

.each ( ) 方法遍历匹配的每一个元素,主要是DOM处理,each每一个 里面的回调函数有两个参数,index为每个元素的索引, demEle是DOM元素对象,不是JQ对象 ,所以想要使用JQ方法,需要转换为JQ对象

$("div").each(function (index, domEle) { xxx; }) 
// domEle当前DOM元素,可以使用this选择器
.each(object,function (index, element) { xxx; })
// object 为遍历的对象

return false 可以提早种终止循环

创建插入删除对象

创建元素 语法: $( " <div> </div> " ) 动态创建了一个div

插入对象 内部添加 (父子关系添加) .append ( "内容" ) // 将内容放入匹配元素内部的最后面(类似原生appendChind) .preprnd ( "内容" ) // 将内容放入匹配元素内部的最前面

外部添加 (兄弟关系添加) .after ( "内容" ) // 将内容放在匹配元素的后面 .before ( "内容" ) // 吧内容放在陪陪元素的前面

删除元素 .remove ( ) // 删除自己 .empty ( ) // 删除匹配元素集合的所有子节点 .html ( " " ) // 清空匹配的元素内容 // .empty() 和 .html("") 作用等价,都可以删除元素里面的内容,只不过html还可以设置内容

$('body').append(" <div class = 'dt'></div> " )//动态创建div并插入
$('.dt').html('123')//给div插入内容
$('.dt').text("<div class = 'dl></div>")//给动态创建的div再插入div

//从缓存中获取对象数组,然后动态渲染插入(购物车)
var gwc = JSON.parse(sessionStorage.getItem( ' data ' ))//从缓存中获取data数组,再转为正常可用的对象数组
$.each(gwc, function (i, e) {//遍历获取的gwc数组,function中i为每个下标,e为每个对象
var str = `
<div class="sp_">
<div class="sp_bj">
<input type="checkbox" class="sp_dx">
<span class="delet ">删除</span>
</div>
<div class="sp_main">
<img src="../imgs/男的allstar.jpg" alt="图片消失了">
<div class="xx">
<h4 class="sp_name">${e.name}</h4><!-- e.neme为每个e对象的name属性 (此处插入属性值) -->
<p>型号:172471C102</p>
<p>颜色:白色</p>
<p>尺码:<span>${e.size}</span></p>
</div>
<div class="jg">
<p>¥<span>${e.oldmoney}</span></p>
<div class="quantity-input">
<span>数量:</span>
<input type="button" value="+" class="pius">
<input type="button" value="1" class="num">
<input type="button" value="-" class="minus quantity-u">
</div>
</div>
</div>
</div>
`
$('.gouwuche_main_sp').append(str)//再将动态字符串逐个插入要插入的盒子中
})


// parseInt() 函数解析字符串并返回整数。

width ( ) / height ( ) // 获取元素的宽高 (只有 width 和 height ) innerWidth ( ) / innerHeight ( ) // 获取宽高(包含padding) outerWidth ( ) / outerHeight ( ) // 获取宽高(包含padding、border) outerWidth ( true ) / outerHeight ( true ) // 获取宽高(含padding、border、margin) 以上参数为空,获取相应值,返回数字型 如果参数为数字,则为修改相应值 参数可不写单位

offset ( ) position ( ) scrollTop ( ) / scrollLeft ( )

offset( ) // 设置或获取 元素偏移 offset( ) 方法设置或返回元素相对于文档的偏移坐标,跟父级没有关系 该方法有两个属性 offset().top 获取距离文档顶部的距离,offset().left 同理 设置元素偏移:offset ( { top : 10 , left : 30 } )

position ( ) 获取元素偏移 position ( ) 用于返回被选元素相对于带有定位的父级偏移坐标,如果父级都没有定位则以文档为准 该方法有两个属性 top left 。position().top 用于获取举例定位父级顶部的距离,position().left 同理 该方法只能获取

scrollTop ( ) / scrollLeft ( ) 设置或获取 元素被卷去的部分 scrollTop() 设置或返回被选元素被卷去的头部 不跟参数是获取,参数为不带单位的数字为设置

on ( ) 绑定事件(事件委托)

on()方法在匹配元素(单个或多个)上绑定一个或多个事件的处理函数 element.on ( events , [ selector ] ,fn ) events:一个或多个用空格分隔的事件类型(例:click keydown) selector:元素的子元素选择器 fn:回调函数,即绑定在元素身上的侦听函数

如果有的事件只想触发一次, 可以使用 one( ) 来绑定事件

//on方法优势1:可以绑定多个事件,多个事件处理程序
$(“div”).on({
mouseover: function(){},
mouseout: function(){},
click: function(){}
});
//如果事件处理程序相同
$(“div”).on(“mouseover mouseout”, function() {
$(this).toggleClass(“current”);
})

//on()方法优势2:事件委托
$('ul').on('click', 'li', function() {
alert('hello world!');
});
//传入子集为事件委托
//不传入事件对象

在此前在此之前有bind(), live() delegate()等方法来处理事件绑定或者事件委派,最新版本的请用on()

//on()方法优势3:给动态创建的元素绑定事件
$("div").append($("<p>我是动态创建的p</p>"));
$("div").on("click","p", function(){
alert("俺可以给动态生成的元素绑定事件")
});

off( ) 解绑事件 off() 方法可以移除通过 on() 方法添加的事件处理程序 $("p").off() // 解绑p元素所有事件处理程序 $("p").off( "click") // 解绑p元素上面的点击事件 后面的 foo 是侦听函数名$("ul").off("click", "li") // 解绑事件委托

自动触发事件trigger ( )

$("p").on("click", function () {//绑定p的click事件
console.log('Hi');
});
//第一种简写形式的自动触发:
$("p").click() //$("p")为一个对象,.click为对象内的属性,属性值为console.log('Hi'); 后加() 触发click

//第二种利用trigger()方法触发
$("p").trigger("click")

//第三种自动触发方式:
$("p").triggerHandler("click") // 第三种自动触发模式
//triggerHandler模式不会触发元素的默认行为,这是和前面两种的区别

JQ事件对象

$( ) .on(events , [ selector ] , function ( event ) { } )

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

//阻止冒泡:
$().stopPropagation()

JQ拷贝对象

$.extend ( [ deep ] , target , object1 , [ objextN ] ) deep: true为深拷贝,false为浅拷贝 target:要拷贝的目标对象 object1:待拷贝到第一个对象的对象

浅拷贝目标对象引用的被拷贝的对象地址,修改的目标会影响被拷贝对象 深拷贝,完全克隆,修改目标对象不会影响被拷贝对象

<script>
var obj1 = {
name:'刘德华',
sex:'男'
}
var obj2 = {
name:'李硕',
sex:'女'
}
var obj3 = {
name:'范冰冰',
sex:'女'
}
$.extend(true,obj1,obj2,obj3)//合并到obj1,obj23没有影响
console.log(obj1)
console.log(obj2)
console.log(obj3)
//true 合并后obj1为 {name: '范冰冰', sex: '女'}
</script>

多库共存(修改JQ符号)

jQuery使用$作为标示符,随着jQuery的流行,其他 js 库也会用这$作为标识符, 这样一起使用会引起冲突 . jQuery 变量规定新的名称:$.noConflict() var xx = $.noConflict(); 将此段代码粘贴在引入的JQ中 来改变JQ的符号

jQuery 插件库 http://www.jq22.com/

jQuery 之家 http://www.htmleaf.com/

重点:瀑布流插件 图片懒加载插件

JQ 效果

//手风琴效果	
<script type="text/javascript">
$(document).ready(function() {//入口函数
$(".box-m").click(function() {
$(".box_").stop().slideUp("slow");//所有上滑
$(this).siblings().stop().slideToggle("slow");//点击的切换
// stop() 停止动画效果
})

});
</script>
//JQ全选效果
<script>
// ('.checkboxAll') //获取总价选框
// ('c_money') //获取总价span
// ('.checkbox') //获取单价选框(数组)
// ('#money') //获取单价(数组)
// console.log($(".checkboxAll").prop('checked'))

var a = 0
$('.checkboxAll').click(function() {
$('.money').each(function() { //先将总钱数累加
a += Number($(this).html())
})
if ($('.checkboxAll')[0].checked) { //如果全选被选中
$('.c_money').text(a) // 设置总价
$('.checkbox').each(function() { //设置所有选框选中
$('.checkbox').prop("checked", $('.checkboxAll').prop("checked"))
})
} else { //选框没有被选中
a = 0
$('.c_money').text(a) // 设置总价
$('.checkbox').each(function() { //设置所有选框选中
$('.checkbox').prop("checked", $('.checkboxAll').prop("checked"))
})
}
})


$('.checkbox').click(function() {
if ($(this).prop('checked')) {//点击的单选被选中
a += Number($('.money').eq($('.checkbox').index(this)).text())//钱数累加
$('.c_money').text(a)//钱数赋值
} else {
a -= Number($('.money').eq($('.checkbox').index(this)).text())//钱数递减
$('.c_money').text(a)//赋值
}
$(".checkbox").each(function(i,e) {//遍历每一个单选框
if ($(".checkbox:checked").length == $(".checkbox").length) {//如果选中的单选框数量等于所有的数量
$(".checkboxAll").prop("checked", true)//全选状态为true
// return
} else {
$(".checkboxAll").prop("checked", false)
}
})
})
</script>

修饰符 i ignore - 不区分大小写 g global - 全局匹配 m multi line - 多行匹配 使边界字符 ^ $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾

/a/g	//全局匹配 a 
/a/gi //全局匹配 a 不区分大小写

\ 将下一个字符标记为一个特殊字符 例如 \n 为换行

^ 输入匹配字符的起始位置 如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置

$ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置

+' 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"

{n} 匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o

{n,} 至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'

{n,m} 最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格

? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。

x|y 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。

[xyz] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'

[ ^xyz] 负值字符集合。匹配未包含的任意字符。例如, ' abc ' 可以匹配 "plain" 中的'p'、'l'、'i'、'n'

[a-z] 字符范围。匹配指定范围内的任意字符

[ ^a-z] 同理

\d 匹配一个数字字符

\D 匹配一个非数字字符

\n 匹配一个换行符

\s 匹配任何空白字符,包括空格、制表符、换页符等等

\S 匹配任何非空白字符

\w 匹配数字、字母、下划线

\W 非数字、字母、下划线

^ 包含一个特殊的字符 ^ ,表示该模式只匹配那些以 once 开头的字符串。例如该模式与字符串 "once upon a time" 匹配,与 "There once was a man from NewYork" 不匹配。正如如 ^ 符号表示开头一样, $ 符号用来匹配那些以给定模式结尾的字符串

$ 只匹配结尾为该条件的

^abc$ 只匹配abc字符串

[a-z] // 匹配所有的小写字母 
[A-Z] // 匹配所有的大写字母
[a-zA-Z] // 匹配所有的字母
[0-9] // 匹配所有的数字
[0-9\.\-] // 匹配所有的数字,句号和减号
[ \f\r\t\n] // 匹配所有的白字符
[^a-z] //除了小写字母以外的所有字符
[^\\\/\^] //除了(\)(/)(^)之外的所有字符
[^\"\'] //除了双引号(")和单引号(')之外的所有字符

/ [ 0-9 ] + / // 是否有0-9的数字(+代表可以有很多个数字) / a / // 是否有 a

		var reg = /a/;
var str = "wrhgatd";
console.log(reg.test(str))//判断str字符串中有没有a

var objRegExp= /^\d+\.\d+$/;// ^ 为起始符 $ 为结束符 \d 为数字 + 代表可以有好几个数字 \.只有一个
var num = 123.23 ;
console.log(objRegExp.test(num))//判断数字间是否带有小数

var reg = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/;//邮箱
name_tj = /^[1][3,4,5,7,8][0-9]{9}$///手机号

一、校验数字的表达式

数字:^[0-9]*$
n位的数字:^\d{n}$
至少n位的数字:^\d{n,}$
m-n位的数字:^\d{m,n}$
零和非零开头的数字:^(0|[1-9][0-9]*)$
非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
非零的负整数:^\-[1-9][]0-9″*$ 或 ^-[1-9]\d*$
非负整数:^\d+$ 或 ^[1-9]\d*|0$
非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
二、校验字符的表达式

汉字:^[\u4e00-\u9fa5]{0,}$
英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
长度为3-20的所有字符:^.{3,20}$
由26个英文字母组成的字符串:^[A-Za-z]+$
由26个大写英文字母组成的字符串:^[A-Z]+$
由26个小写英文字母组成的字符串:^[a-z]+$
由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
可以输入含有^%&',;=?$\”等字符:[^%&',;=?$\x22]+
禁止输入含有~的字符:[^~\x22]+
三、特殊需求表达式

Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
电话号码(“XXX-XXXXXXX”、”XXXX-XXXXXXXX”、”XXX-XXXXXXX”、”XXX-XXXXXXXX”、”XXXXXXX”和”XXXXXXXX):^($$\d{3,4}-)|\d{3.4}-)?\d{7,8}$
国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
身份证号(15位、18位数字):^\d{15}|\d{18}$
短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
日期格式:^\d{4}-\d{1,2}-\d{1,2}
一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
钱的输入格式:

有四种钱的表示形式我们可以接受:”10000.00″ 和 “10,000.00″, 和没有 “分” 的 “10000″ 和 “10,000″:^[1-9][0-9]*$
这表示任意一个不以0开头的数字,但是,这也意味着一个字符”0″不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
必须说明的是,小数点后面至少应该有1位数,所以”10.”是不通过的,但是 “10″ 和 “10.2″ 是通过的:^[0-9]+(.[0-9]{2})?$
这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
这样就允许用户只写一位小数。下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
备注:这就是最终结果了,别忘了”+”可以用”*”替代。如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
中文字符的正则表达式:[\u4e00-\u9fa5]
双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
空白行的正则表达式:\n\s*\r (可以用来删除空白行)
HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)
IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))
四、字母,数字,下划线或者数字的正则表达式



1.由数字、26个英文字母或者下划线组成的字符串:

^[0-9a-zA-Z_]{1,}$
2.非负整数(正整数 + 0 ):
^/d+$
3. 正整数:
^[0-9]*[1-9][0-9]*$
4.非正整数(负整数 + 0):
^((-/d+)|(0+))$
5. 负整数 :
^-[0-9]*[1-9][0-9]*$
6.整数:
^-?/d+$
7.非负浮点数(正浮点数 + 0):
^/d+(/./d+)?$
8.正浮点数 :
^(([0-9]+/.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*))$
9. 非正浮点数(负浮点数 + 0):
^((-/d+(/./d+)?)|(0+(/.0+)?))$
10.负浮点数 :
^(-(([0-9]+/.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*/.[0-9]+)|([0-9]*[1-9][0-9]*)))$
11. 浮点数 :
^(-?/d+)(/./d+)?$
12.由26个英文字母组成的字符串 :
^[A-Za-z]+$
13. 由26个英文字母的大写组成的字符串 :
^[A-Z]+$
14.由26个英文字母的小写组成的字符串 :
^[a-z]+$
15. 由数字和26个英文字母组成的字符串 :
^[A-Za-z0-9]+$
16.由数字、26个英文字母或者下划线组成的字符串 :
^/w+$
17.email地址 :
^[/w-]+(/.[/w-]+)*@[/w-]+(/.[/w-]+)+$
18.url:
^[a-zA-z]+://(/w+(-/w+)*)(/.(/w+(-/w+)*))*(/?/S*)?$
19. 年-月-日:
/^(d{2}|d{4})-((0([1-9]{1}))|(1[1|2]))-(([0-2]([1-9]{1}))|(3[0|1]))$/
20.月/日/年:
/^((0([1-9]{1}))|(1[1|2]))/(([0-2]([1-9]{1}))|(3[0|1]))/(d{2}|d{4})$/
21.Emil:
^([w-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([w-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)$
22. 电话号码:
(d+-)?(d{4}-?d{7}|d{3}-?d{8}|^d{7,8})(-d+)?
23.IP地址:
^(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5])$
24. 匹配中文字符的正则表达式:
[/u4e00-/u9fa5]
25.匹配双字节字符(包括汉字在内):
[^/x00-/xff]
26. 匹配空行的正则表达式:
/n[/s| ]*/r
27.匹配HTML标记的正则表达式:
/<(.*)>.*<///1>|<(.*) //>/
28.匹配首尾空格的正则表达式:
(^/s*)|(/s*$)
29.匹配Email地址的正则表达式:
/w+([-+.]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)*
30. 匹配网址URL的正则表达式:
^[a-zA-z]+://(//w+(-//w+)*)(//.(//w+(-//w+)*))*(//?//S*)?$
31. 匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):
^[a-zA-Z][a-zA-Z0-9_]{4,15}$
32. 匹配国内电话号码:
(/d{3}-|/d{4}-)?(/d{8}|/d{7})?
33.匹配腾讯QQ号:
^[1-9]*[1-9][0-9]*$
34. 只能输入数字:
^[0-9]*$
35.只能输入n位的数字:
^/d{n}$
36.只能输入至少n位的数字:
^/d{n,}$
37.只能输入m~n位的数字:
^/d{m,n}$
38.只能输入零和非零开头的数字:
^(0|[1-9][0-9]*)$
39.只能输入有两位小数的正实数:
^[0-9]+(.[0-9]{2})?$
40. 只能输入有1~3位小数的正实数:
^[0-9]+(.[0-9]{1,3})?$
41.只能输入非零的正整数:
^/+?[1-9][0-9]*$
42. 只能输入非零的负整数:
^/-[1-9][0-9]*$
43.只能输入长度为3的字符:
^.{3}$
44. 只能输入由26个英文字母组成的字符串:
^[A-Za-z]+$
45.只能输入由26个大写英文字母组成的字符串:
^[A-Z]+$
46. 只能输入由26个小写英文字母组成的字符串:
^[a-z]+$
47.只能输入由数字和26个英文字母组成的字符串:
^[A-Za-z0-9]+$
48. 只能输入由数字和26个英文字母或者下划线组成的字符串:
^/w+$
49.验证用户密码(正确格式为: 以字母开头,长度在5~17 之间,只能包含字符、数字和下划线)
^[a-zA-Z]/w{5,17}$
50.验证是否包含有 ^%&',;=?$/"等字符:
[^%&',;=?$/x22]+
51.只能输入汉字:
^[\u4e00-\u9fa5]{0,}$
52、只含有汉字、数字、字母、下划线不能以下划线开头和结尾
^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$
53、只含有汉字、数字、字母、下划线,下划线位置不限
^[a-zA-Z0-9_\u4e00-\u9fa5]+$
54、2~4个汉字
@"^[\u4E00-\u9FA5]{2,4}$

AJAX = Asynchronous JavaScript and XML( 异步 的 JavaScript 和 XML)现为JS和JSON 优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容 以JS为底层,JQ封装了AJAX方法

在没有AJAX前使用表单传递数据,但是表单不能实现异步。会跳转

前端与服务器之间存在跨域问题,服务器之间不存在跨域问题

get/post 方法

JQuery 封装的AJAX

$.ajax() 方法

type:

1. ' get ' (查看)会向数据库发索取数据的请求,从而来获取信息。只是用来查询一下数据,不会修改、增加数据,不会影响资源的内容,即该请求不会产生副作用。无论进行多少次操作,结果都是一样的
2. ’ put ‘ (更新)向服务器端发送数据的,从而改变信息.用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同
3. ' post ' (创建)向服务器端发送数据的,但是该请求会改变数据的种类等资源,会创建新的内容。几乎目前所有的提交操作都是用POST请求的
4. ' delete ' (删除)删除某一个资源的
$.ajax({//AJAX方法,内为对象
type:'get',//AJAX类型,此处为获取(共有四种类型,常用两种)默认get
url:'1.json',//获取地址
data:{},//传递参数
dataType:"json",
async:true,//是否异步
success:function(res){//成功获取后执行函数
console.log(res);//res为获取到的数据对象,需要逐层找到需要使用的信息
},
error:function(res){//获取失败后执行函数
console.log(res);//打印res可以获得详细的错误详情
}
})

$.get ( ) 和 $.post ( ) 是简易写法,高层的实现,在调用他们的时候,会运行底层封装好的$.ajax

$.get ( ) 方法 - 从指定的资源请求数据 (基本用于取回数据,可能返回缓存数据) $.get() 方法通过 HTTP GET 请求从服务器上请求数据

$("button").click(function(){
$.get("demo_test.php",function(data,status){//get()的第一个参数为请求的地址 第二个是回调函数
alert("数据: " + data + "\n状态: " + status);//函数内的data存有被请求页面的内容 status 存有请求的状态
});
});

$.post( ) 方法 - 向指定的资源提交要处理的数据(也可用于获取数据,但post不会缓存数据,且常用于联通请求一起发送数据) $.post() 方法通过 HTTP POST 请求向服务器提交数据

$("button").click(function(){
$.post("/try/ajax/demo_test_post.php",//第一个参数为希望请求的地址
{//此对象为请求,连同请求一起发送数据
name:"菜鸟教程",
url:"http://www.runoob.com"
},
function(data,status){//data存有被请求页面的内容 status 存有请求的状态
alert("数据: \n" + data + "\n状态: " + status);
});
});

原生AJAX

get请求方式:


function ajax() {
//创建核心对象
xhr = null;
if(window.XMLHttpRequest){//新版本浏览器可以直接创建对象,判断此浏览器有没有此对象
xhr = new XMLHttpRequest();//创建对象
}else if(window.ActiveXObject){//IE5或IE6没有XMLHttpRequest对象
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
//编写回调函数
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){//readystate 判断XMLHttpRequest 状态 (4为请求完成且响应就绪) xhr.status:获取当前服务器的响应状态 200=>成功
console.log(xhr.responseText)//打印获取的数据
}
}
//设置open请求方式和请求路径
xhr.open("get","/Ajax/ajax?userId=10",true);//一个URL还传递了数据,true为异步
//send发送
xhr.send();
}

post请求方式

function ajax() {
//创建核心对象
xhr = null;
if (window.XMLHttpRequest) {//新版本浏览器可以直接创建对象,判断此浏览器有没有此对象
xhr = new XMLHttpRequest();//创建对象
} else if (window.ActiveXObject) {//IE5或IE6没有XMLHttpRequest对象
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
//编写回调函数

xhr.onreadystatechange = function(){
if (xhr.readyState == 4 && xhr.status == 200) {//readystate 判断XMLHttpRequest 状态 (4为请求完成且响应就绪) xhr.status:获取当前服务器的响应状态 200=>成功
console.log(xhr.responseText)//打印获取的数据
}
}
//open设置请求方式和请求路径
xhr.open("post","/Ajax/ajax2",true)//一个servlet true为异步
//设置请求头(POST)
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
//send发送
xhr.send("userId = 10");
}

readystate : 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化 0 :请求未初始化 1 :服务器已建立 2 :请求已接收 3 :请求处理中 4 :请求已完成,且响应已就绪

status : 200 : ' OK ' 404 : 未找到页面 405 : 请求方式不正确 500 : 服务器内部错误 403 : 禁止请求

封装好的原生ajax方法

function ajax(url){
//创建XMLHttpRequest对象,新版本浏览器直接创建,IE5 IE6创建ActiveXObject对象
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : ActiveXObject("microsoft.XMLHttp")
xhr.open("get",url,true);
xhr.send();//发送请求
xhr.onreadystatechange = () => {
if(xhr.readyState == 4){//返回存有 XMLHttpRequest 的状态
if(xhr.status == 200){//返回状态码
var data = xhr.responseText;
return data;
}
}
}
}

表单的提交方法(了解)

<form action="http://localhost:3000/regist" method="post">
<p>
手机:
<input placeholder="请输入手机号码" type="text" name="phone" id="phone" value="" />
<p class="yzp" style='font-size: 10px;color: red;'></p>

</p>
<p>
用户:
<input placeholder="请用户名" type="text" name="user_name" id="user_name" value="" />
<p class="yzp" style='font-size: 10px;color: red;'></p>

</p>
<p>
密码:
<input placeholder="密码" type="text" name="user_pwd" id="user_pwd" value="" />
<p class="yzp" style='font-size: 10px;color: red;'></p>

</p>

<input type="submit" value="注册"/>
</form>

ES6语法(ECMAScript)

ES6 是 JavaScript 语言的下一代标准,使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

let 与 const 声明

let 用来声明变量,但是所声明的变量只在命令所在的代码块内有效,没有变量提升

//for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域
for (let i = 0; i < 3; i++) {//父作用域
let i = 'abc';//子作用域
console.log(i);
}
// abc(将会打印三遍)
// abc
// abc

var 命令会发生 “变量提升” 现象,即变量可以在声明之前使用,值为undefined 为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在 声明后 使用,否则报错

暂时性死区 只要块级作用域内存在 let 命令,它所声明的变量就“绑定” (binding) 这个区域,不再受外部的影响

var tmp = 123;//全局声明变量

if (true) {
tmp = 'abc'; // ReferenceError
let tmp;// let 声明的 tmp 绑定了这个区域,所以4行代码将会报出赋值错误
}
//存在全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,导致后者绑定这个块级作用域,所以在let声明变量前,对tmp赋值会报错

在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)

不允许重复声明 块级作用域 ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域 ES5 只有 全局作用域 函数作用域 ,没有块级作用域,这带来很多不合理的场景:

内层变量可能会覆盖外层变量

用来计数的循环变量泄露为全局变量

const声明常量

const 声明一个只读的 常量 。一旦声明,常量的值就不能改变。 const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即 初始化 (赋值),不能留到以后赋值。

只在声明所在的块级 作用域 内有效。 不提升,同样存在暂时性死区

本质 const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心

字符串的扩展

字符串模板

const box = document.querySelector(".box");
let id = 1;
let title = "腾讯新闻";
let str = "";
str = `
<ul>
<li>
<p id = "${id}">${title}</p>
</li>
</ul>
`;
box.innerHTML = str;

字符串的遍历接口

字符串可以被 for...of 循环遍历

var str = 'foo';
for (let x of str) {
console.log(x)
}
// "f"
// "o"
// "o"

除了遍历字符串,这个遍历器最大的优点是可以识别大于 0xFFFF 的码点,传统的 for 循环无法识别这样的码点

repeat ( ) 重复方法

repeat 方法返回一个新字符串,表示将原字符串重复 n

'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""

padStart(),padEnd() 补全字符串

ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。 padStart() 用于头部补全, padEnd() 用于尾部补全 第一个参数为字符串的最大长度 第二个参数为补全字符串的字符 第二个参数为空时默认用空格补全字符串

'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
//在开头补全
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
//在末尾补全

//如果原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串。
'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'


//padStart()的常见用途是为数值补全指定位数。下面代码生成 10 位的数值字符串。
'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"
'123456'.padStart(10, '0') // "0000123456"


//另一个用途是提示字符串格式。
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"

trim()清除字符串空格

const s = '  abc  ';
s.trim() // "abc" 清除所有空格
s.trimStart() // "abc " 清除前端空格
s.trimEnd() // " abc" 清除后端空格

Math 对象的扩展

Math.trunc 方法用于去除一个数的小数部分,返回整数部分

Math.trunc(4.1) // 4
Math.trunc('123.456') // 123
Math.trunc(false) // 0
//对于空值和无法截取整数的值,返回NaN
Math.trunc('foo'); // NaN

Math.sign 方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值

//参数为正数,返回+1;
Math.sign(-5) // -1
//参数为负数,返回-1;
//参数为 0,返回0;
//参数为-0,返回-0;
//其他值,返回NaN

函数的扩展

//1.带参数默认值的函数
//es5写法
// function add(a,b){
// a= a||2;
// b=b||6;
// return a+b;
// }
// es6
function add(a=1,b=6){
return a+b;
}
console.log(add(3))//9 a = 3 (赋值); b = 6 (默认)
console.log(add(3,3))
//		2.默认的表达式也可以是一个函数
function add(a,b=getVal(2)){//a = 10
return a+b;
}
function getVal(val){
return val+5;
}
console.log(add(10))//17

ES6 引入 rest 参数(形式为 ...变量名 ),用于获取函数的多余参数,这样就不需要使用 arguments 对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中

//		3.剩余参数(剩余运算符)(有三个点... 和紧跟着的参数指定  ...keys)
//		4.扩展运算符  
const MaxNum = Math.max(50,20);
console.log(MaxNum);
// es5处理数组中的最大值 ,使用apply
const arr = [1,2,4,7,100,40];
// const maxNum = Math.max(arr);会报错哦
const maxNum = Math.max.apply(null,arr);
console.log(maxNum);
// es6扩展运算符
console.log(Math.max(...arr));

箭头函数没有this指向,在哪个作用域声明的箭头函数,箭头函数的this就指向谁。若外部没有作用域(函数作用域),this会一直指向window

箭头函数不是函数,是一个表达式。所以没有arguments,也没有作用域链

箭头函数没有构造器,因此不能使用new关键字实例化对象

//		5.es6中使用箭头函数
// let add = function(a,b){
// return a+b;
// }
// 两个参数
// let add = (a,b)=>{
// return a+b;
// }
// let add = (a,b)=>(a+b);
// let add = (a,b)=>a+b;
// console.log(add(2,3))



// 一个参数
// let add = val=>val
// console.log(add(5))//5
let add = val=>(val+5)
console.log(add(10))//15



// 无参数
// let fn = ()=>{
// return "haha";
// }
// let fn = ()=> "haha";
// let fn = ()=>"haha"+123;
// console.log(fn())
let getObj = (id)=>{
return {
id:id,
name:"张三"
}
}
// 简单写法,一定要加();
// let getObj = (id)=>({id:id,name:"张三"})
console.log(getObj(2))

箭头函数的this指向

箭头函数体内的 this 对象,就是 定义该函数时所在的作用域指向的对象 ,而不是调用时所在的作用域指向的对象。

var name = 'window'; 

var A = {
name: 'A',
sayHello: () => {
console.log(this.name)
}
}

A.sayHello();//输出的是window
//"定义该函数所在的作用域指向的对象”,作用域是指函数内部,这里的箭头函数,也就是sayHello,所在的作用域其实是最外层的js环境,因为没有其他函数包裹;然后最外层的js环境指向的对象是winodw对象,所以这里的this指向的是window对象
若要绑定A对象:
var name = 'window';

var A = {
name: 'A',
sayHello: function(){
var s = () => console.log(this.name)
return s//返回箭头函数s
}
}

var sayHello = A.sayHello();
sayHello();// 输出A

var B = {
name: 'B';
}

sayHello.call(B); //不管是谁调用,this指向都是A
sayHello.call(); //还是A

数组的扩展

扩展运算符

扩展运算符(spread)是三个点( ... )。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列 该运算符主要用于函数调用 (传递参数) 只有函数调用时,扩展运算符才可以放在圆括号中,否则会报错 替代函数的 apply 方法

console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]
function add2(...args){
console.log(args);//['a', 'b', 'c']
console.log(arguments);//Arguments(3) ['a', 'b', 'c', callee: (...), Symbol(Symbol.iterator): ƒ]
}

add2("a","b","c");
let arr = [1,2,3,4,5,6,7,8,9]
let max = Math.max(...arr)//此处如果传入arr将会报错
console.log(max)//9
//参数接收的arguments为伪数组,而...keys 为真正的数组

扩展运算符可以用来 合并数组 ( 两种方法都是浅拷贝 )

const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];
// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]

扩展运算符 与解构赋值结合

const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
const [first, ...rest] = [];
first // undefined
rest // []
const [first, ...rest] = ["foo"];
first // "foo"
rest // []

如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错

const [...butLast, last] = [1, 2, 3, 4, 5];
// 报错
const [first, ...middle, last] = [1, 2, 3, 4, 5];
// 报错

将字符串转为数组

[...'hello']
// [ "h", "e", "l", "l", "o" ]

数组的空位

数组的空位指,数组的某一个位置没有任何值。比如, Array 构造函数返回的数组都是空位

Array(3) // [, , ,]

ES5不识别空位 ES6将空位转为undefind 扩展运算符( ... )也会将空位转为 undefined copyWithin() 会连空位一起拷贝 for...of 循环也会遍历空位。

from()转化数组

Array.from 方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。

let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']



// NodeList对象
let ps = document.querySelectorAll('p');//获取所有的p标签
Array.from(ps).filter(p => {//from转换为数组 filter将不符合要求的p元素从数组中去除
return p.textContent.length > 100;
});
// arguments对象
function foo() {
var args = Array.from(arguments);//将参数存储的伪数组转换为真正的数组
}

//将字符串转换为数组
Array.from('hello')//更建议使用{...str}的方法
// ['h', 'e', 'l', 'l', 'o']

copyWithin()数组内部覆盖

Array.copyWithin(target, start = 0, end = this.length)
// target(必需):从该位置开始替换数据。如果为负值,表示倒数。
// start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示从末尾开始计算。
// end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示从末尾开始计算。

find() 和 findIndex()

数组实例的 find 方法,用于找出 第一个 符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为 true 的成员,然后返回该成员。如果没有符合条件的成员,则返回 undefined

[1, 4, -5, 10].find((n) => n < 0)
// -5

find 方法的回调函数可以接受三个参数 ,依次为当前的值、当前的位置和原数组。

[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10

数组实例的 findIndex 方法的用法与 find 方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回 -1

fill()填充数组

fill 方法使用给定值,填充一个数组。数组中已有的元素,会被全部抹去。

['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]

fill 方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。

['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']

注意,如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象。

includes() 数组包含

传入一个值时

[1, 2, 3].includes(2)     // true
[1, 2, 3].includes(4) // false
[1, 2, NaN].includes(NaN) // true

该方法的第二个参数表示搜索的起始位置,默认为 0 。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为 -4 ,但数组长度为 3 ),则会重置为从 0 开始。

[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true 从倒数第一位开始找

flat() 拉开多维数组

用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。

[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]

默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将 flat() 方法的参数写成一个整数,表示想要拉平的层数,默认为1。

[1, 2, [3, [4, 5]]].flat()
// [1, 2, 3, [4, 5]]
[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]

如果不管有多少层嵌套,都要转成一维数组,可以用 Infinity 关键字作为参数。

[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]

如果原数组有空位, flat() 方法会跳过空位。

[1, 2, , 4, 5].flat()
// [1, 2, 4, 5]

entries() keys() values() ——用于遍历数组。 它们都返回一个遍历器对象 可以用 for...of 循环进行遍历,唯一的区别是 keys() 是对键名的遍历、 values() 是对键值的遍历, entries() 是对键值对的遍历。

entries()

Object.entries() 方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致( 区别在于 for-in 循环还会枚举原型链中的属性)

var obj = {
name:'lishuo',
age:22
}
console.log(Object.entries(obj))
// ['name', 'lishuo']
// ['age', 22]
//返回为数组


var obj = {
name: 'lishuo',
age: 22
}
for (const [key, value] of Object.entries(obj)) {
console.log(`${key}: ${value}`);
}
// name: lishuo
// age: 22
//返回为字符串
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"

对象的扩展

属性的简介表示

在大括号里面,直接写入变量和函数,作为对象的属性和方法。

	//属性简写
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于
const baz = {foo: foo};


//属性简写
function f(x, y) {
return {x, y};
}
// 等同于
function f(x, y) {
return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}


//方法简写
const o = {
method() {
return "Hello!";
}
};
// 等同于
const o = {
method: function() {
return "Hello!";
}
};
const student = {//const存储的是对象的指针,并不是对象本身,所以该对象内容可以被改变。使用const声明对象只能保证该指针不会被改变
num:22,
getnum(){
return this.num;
},
setnum(num){
this.num = num
return `num:${this.num}`
}
}
student.setnum(5);
console.log(student.getnum());

属性名表达式

旧方法定义对象属性:

// 方法一
obj.foo = true;
// 方法二
obj['a' + 'bc'] = 123;
//方法三
var obj = {
foo: true,
abc: 123
};

允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内。

let propKey = 'foo';
let obj = {
[propKey]: true,// foo:true
['a' + 'bc']: 123,// abc:123
['h' + 'ello']() { //hello:function(){}
return 'hi';
}
};

注意,属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串 [object Object] ,这一点要特别小心。

const keyA = {a: 1};
const keyB = {b: 2};
const myObject = {
[keyA]: 'valueA',
[keyB]: 'valueB'
};
myObject // Object {[object Object]: "valueB"}

方法的name属性

const person = {
sayName() {
console.log('hello!');
},
};
person.sayName.name // "sayName"

对象的super指向

this 关键字总是指向函数所在的当前对象,ES6 又新增了另一个类似的关键字 super ,指向当前对象的原型对象。

对象内的扩展运算符

对象的扩展运算符( ... )用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }

由于数组是特殊的对象,所以对象的扩展运算符也可以用于数组。

let foo = { ...['a', 'b', 'c'] };
foo
// {0: "a", 1: "b", 2: "c"}
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

//解构赋值要求等号右边是一个对象,所以如果等号右边是undefined或null,就会报错,因为它们无法转为对象。
//解构赋值必须是最后一个参数,否则会报错。
//解构赋值为浅拷贝!

对象的遍历

ES2017 引入 了跟 Object.keys 配套的 Object.values Object.entries ,作为遍历一个对象的补充手段,供 for...of 循环使用。

对象的新增方法

is() 判断全等

它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。

+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

assign() 对象合并

将源对象(source)的所有可枚举属性,复制到目标对象(target)。

const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

第一个参数是目标对象,后面的参数都是源对象。 注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。 如果该参数不是对象,则会先转成对象,然后返回。

剩余操作符:...

写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []



//不完全解构

let [x, y] = [1, 2, 3];
x // 1
y // 2

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4

解构赋值允许默认值

let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'

//注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效
//上面代码中,如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined
例:
let [x = 1] = [undefined];
x // 1

let [x = 1] = [null];
x // null

解构赋值(对象)

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值

let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"
let { baz } = { foo: 'aaa', bar: 'bbb' };
baz // undefined


//对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
//上面代码中,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。


//与数组一样,解构也可以用于嵌套结构的对象
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};

let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"



//默认值
var {x = 3} = {};
x // 3
var {x, y = 5} = {x: 1};
x // 1
y // 5
var {x: y = 3} = {};
y // 3
var {x: y = 3} = {x: 5};
y // 5

解构赋值(注意)

如果要将一个已经声明的变量用于解构赋值,必须非常小心

// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

上面代码的写法会报错,因为 JavaScript 引擎会将 {x} 理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题

// 正确的写法
let x;
({x} = {x: 1});

由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。

let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3
// 2行中 0为匹配模式,first才是变量,值为1

解构赋值(字符串)

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。 类似数组的对象都有一个 length 属性,因此还可以对这个属性解构赋值。

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

let {length : len} = 'hello';
len // 5

解构赋值(函数)

新的数据类型 Symbol

JavaScript标准中规定对象的key只能是 String Symbol 类型,区别在于 String 类型的key可以重复而 Symbol 类型的key是唯一的。 Symbol 的本质是表示一个 唯一标识 。每次创建一个Symbol,它所代表的值都不可能重复

const sym = Symbol();
const sym = Symbol('cat');
//传入一个字符串参数(descriptor)用于描述该Symbol:
console.log(sym)//Symbol(cat)

最大的用途就是用来定义对象的私有属性

const name = Symbol("name");
const name2 = Symbol("name");
console.log(name === name2);//false
//其内存地址不相同

Symbol属性无法正常遍历 不易操作,因此不常用

获取Symbol属性可以使用特定的方法Object.getOwnPropertySymbols()

	var Obj = {
}
var a = Symbol("a");
Obj[a] = '123'
var objectSymbols = Object.getOwnPropertySymbols(Obj);
console.log(objectSymbols.length)//1
console.log(objectSymbols)//[Symbol(a)]

获取Symbol属性也可以使用反射

const name = Symbol("name");
const age = Symbol("age");
let person = {
[name]:"张三",
[age]:"10",
sex:"男"
};


let kk = Reflect.ownKeys(person);//遍历键
console.log(kk);//Array(3)["sex" , Symbol(name) , Symbol(age)]

for(let i=0;i<kk.length;i++){
let k = kk[i];//获得键
let v = person[k];//获得值 = person[Symbol(name)]
k = k.toString();
console.log(k+"="+v);
}
//sex=男
//Symbol(name)=张三
//Symbol(age)=10

Promise 对象

Promise ,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果

Promise 对象的特点:

1.对象的状态不受外界影响。 Promise 对象代表一个异步操作,有三种状态: pending (进行中)、 fulfilled (已成功)和 rejected (已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

2.一旦状态改变,就不会再变,任何时候都可以得到这个结果。 Promise 对象的状态改变,只有两种情况:进行中到已成功、进行中到已失败。只要这两种情况发生,状态就凝固了,不会再改变。

Promise 对象的缺点: 1.无法取消 Promise 一旦新建它就会立即执行,无法中途取消。 2.如果不设置回调函数, Promise 内部抛出的错误,不会反应到外部。 3.当处于 pending (进行中)状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

ES6 规定, Promise 对象是一个构造函数,用来生成 Promise 实例。

//创建promise对象

var myFirstPromise = new Promise(function(resolve, reject){
//当异步代码执行成功时,我们才会调用resolve(...), 当异步代码失败时就会调用reject(...)
//在本例中,我们使用setTimeout(...)来模拟异步代码,实际编码时可能是XHR请求或是HTML5的一些API方法.
setTimeout(function(){
resolve("成功!"); //代码正常执行!
}, 250);
});

myFirstPromise.then(function(successMessage){
//successMessage的值是上面调用resolve(...)方法传入的值.
//successMessage参数不一定非要是字符串类型,这里只是举个例子
document.write("Yay! " + successMessage);
});



//创建promise对象
let p = new Promise((resolve,reject)=>{
setTimeout(() => {//模拟异步操作
reject('失败');
resolve('成功')
}, 2000);
})
p.then((res)=>{
console.log(res);//成功
})

对于已经实例化过的 promise 对象可以调用 promise.then() 方法,传递 resolve 和 reject 方法作为回调。

then() 方法返回一个 Promise 。它最多需要有两个参数:Promise 的成功和失败情况的回调函数。

then方法可以链式操作

const promise1 = new Promise((resolve, reject) => {
resolve('Success!');//成功时返回
reject('error!');//失败时返回
});

promise1.then((value) => {//接收返回值
console.log(value);
// expected output: "Success!"
});

语法:promise.then(onCompleted, onRejected); 参数:

promise必需。Promise 对象。

onCompleted必需。承诺成功完成时要运行的履行处理程序函数。

onRejected可选。承诺被拒绝时要运行的错误处理程序函数

resolve()方法

resolve()方法可以把任何对象转化成 Promise 对象

let p = Promise.resolve("啊哈哈");
let p = new Promise(resolve=>resolve("foo"));

p.then((res)=>{
console.log(res);
})



Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))

如果参数是 Promise 实例 ,那么 Promise.resolve 将不做任何修改、原封不动地返回这个实例。

参数是一个 thenable 对象 ,( thenable 对象指的是具有 then 方法的对象),会将这个对象转为 Promise 对象,然后就立即执行 thenable 对象的 then 方法。

参数不是具有 then 方法的对象,或根本就不是对象 ,方法返回一个新的 Promise 对象,状态为 resolved

不带有任何参数 ,方法允许调用时不带参数,直接返回一个 resolved 状态的 Promise 对象。

reject() 方法

返回一个新的 Promise 实例,该实例的状态为 rejected

const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s) {
console.log(s)
});
// 出错了

注意, Promise.reject() 方法的参数,会原封不动地作为 reject 的理由,变成后续方法的参数。这一点与 Promise.resolve 方法不一致。

all() 方法

用于将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.all([p1, p2, p3]);
//p1 p2 p3 都是 promise 实例
//如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

p 的状态由 p1 p2 p3 决定,分成两种情况: (1)只有 p1 p2 p3 的状态都变成 fulfilled (成功), p 的状态才会变成 fulfilled ,此时 p1 p2 p3 的返回值组成一个数组,传递给 p 的回调函数。

(2)只要 p1 p2 p3 之中有一个被 rejected (失败), p 的状态就变成 rejected ,此时第一个被 reject 的实例的返回值,会传递给 p 的回调函数。

注意,如果作为参数的 Promise 实例,自己定义了 catch 方法,那么它一旦被 rejected ,并不会触发 Promise.all() catch 方法。(执行自己的catch)

catch() 方法

Promise.prototype.catch() 方法是 .then(null, rejection) .then(undefined, rejection) 的别名,用于指定发生错误时的回调函数。

getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});

上面代码中, getJSON() 方法返回一个 Promise 对象,如果该对象状态变为 resolved ,则会调用 then() 方法指定的回调函数;如果异步操作抛出错误,状态就会变为 rejected ,就会调用 catch() 方法指定的回调函数,处理这个错误。另外, then() 方法指定的回调函数,如果运行中抛出错误,也会被 catch() 方法捕获。

race() 方法

Promise.race() 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

上面代码中,只要 p1 p2 p3 之中有一个实例率先改变状态, p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数。

下面是一个例子,如果指定时间内没有获得结果,就将 Promise 的状态变为 reject ,否则变为 resolve

const p = Promise.race([
fetch('/resource-that-may-take-a-while'),
new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('request timeout')), 5000)
})
]);
p
.then(console.log)
.catch(console.error);
//如果 5 秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数。

Promise 用法示例

//		封装一个ajax方法
const getJson=(url)=>{
let p = new Promise((resolved,rejected)=>{
const xhr = new XMLHttpRequest();
xhr.open("GET",url);
xhr.onreadystatechange = handler;
xhr.responseType ="json";
xhr.setRequestHeader("Accept","application/json");
xhr.send()
function handler(){
// console.log(this)
if(this.readyState==4){
if(this.status==200){
resolved(this.response)
}else{
// rejected(new Error(this.statusText))
rejected(new Error("数据为空"))
}
}
}
})
return p;
}

let p = getJson("https://api.apiopen.top/videoHomeTab");
p.then((res)=>{
console.log(res)
},(error)=>{
console.log(error)
})

Set 集合

表示无重复数值的有序列表,不是键值对的形式存储

var set = new Set();
set.add(666);
set.add("哈哈");
set.add("张三");
set.add("张三");
set.add("张三");
set.add("张三");
console.log(set);//666 哈哈 张三
console.log(set.has(666));//是否有666 true
console.log(set.delete(222));//删除集合中的222 false 集合中没有222

set集合中 键就是值 值就是键 所以一般不用forEach遍历

set.forEach((v,k)=>{
console.log(k,v);
})
//666 666
//哈哈 哈哈
//张三 张三

可以使用for...of 遍历

for (const v of set) {
console.log(v);
}
//666
//哈哈
//张三

因为set集合为没有重复数值的有序列表,所以可以用来数组去重

let arr = [1,1,2,2,3,4,5,6,7,7]
let set = new Set(arr)//将数组转为set集合
console.log(set)//此时打印的set集合已经没有重复
var arr1 = [...set]//将set集合转为数组
console.log(arr1)//打印去重后的新数组

Map集合

Map集合是键值对的有序列表,键和值是任意类型

let haha = new Map();
//存值
haha.set("name","张三");
haha.set("age",10);
console.log(haha);
//Map(2) {'name' => '张三', 'age' => 10}


console.log(haha.get("name"));// 张三 获取name
console.log(haha.has("name"));// true 是否有name
console.log(haha.delete("name"));// true 删除name键值对
let m = new Map([
["a",1],
["b",2]
]);
console.log(m);
//Map(2) {'a' => 1, 'b' => 2}

WeakMap()和WeakSet()

for...in

用于对象,for...of 用于所有可迭代对象

for...in 语句用于对象的属性进行循环操作。 其语法如下:
for (var k (变量名) in 对象名字) {//变量 == 对象中所有的属性名
console.log(对象名[k]) // 在此执行代码,ls[k] 为属性值
}





var obj = {a:1, b:2, c:3};

for (var prop in obj) {
console.log("obj." + prop + " = " + obj[prop]);
}

for...of

for...of 语句 在可迭代对象(包括 Array Map Set String TypedArray arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句

const array1 = ['a', 'b', 'c'];

for (const element of array1) {
console.log(element);
}
// a
// b
// c

迭代器 Iterator

现在有数组、对象、Map、Set、四种数据组合,他们还可以互相嵌套。需要一个统一的接口机制,来处理所有的数据结构 遍历器(Iterator)就是这样一种机制

Iterator的作用有三个: 一是为各种数据结构,提供一个统一的、简便的访问接口; 二是使得数据结构的成员能够按某种次序排列; 三是ES6创造了一种新的遍历命令 for...of 循环,Iterator接口主要供 for...of 消费

    var arr = ['a','b','c']
let it = arr[Symbol.iterator]();//人为创建迭代器
console.log(it.next());//创建迭代器后可以异步迭代
console.log(it.next());
console.log(it.next());
//注意:迭代器要用第三方变量接,不然每一次调用next()都相当于第一次调用

注意:有迭代器 Iterator 才能使用迭代 上面的代码人为创建了一个迭代器 下面的 keys() values() entries() 方法使用后自动创建了迭代器。可以直接迭代

1.迭代器是一个接口,能快捷的访问数据,通过Symbol.iterator来创建迭代器 , 通过迭代器的next()方法来获取迭代之后的结果. 2.迭代器是用于遍历数据结构的指针(数据库的游标)

keys() values() entries() 方法的使用:

let arr = [666,222,33,55];

let it = arr.keys();//使用keys()后数组有可迭代的接口(Interator接口),可以用来迭代
console.log(it);
console.log(it.next());//迭代

let it = arr.values();//使用values()后数组有可迭代的接口,可以用来迭代
console.log(it);
console.log(it.netx());//迭代

let it = arr.entries();//使用entries()后数组有可迭代的接口,可以用来迭代
console.log(it);
console.log(it.next());//迭代

Object.keys

Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致

Object.values

Object.values() 方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用 for...in 循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。

Object.entries

Object.entries() 方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致( 区别在于 for-in 循环还会枚举原型链中的属性)

var obj = {
name:'lishuo',
age:22
}
console.log(Object.entries(obj))
// ['name', 'lishuo']
// ['age', 22]
//返回为数组


var obj = {
name: 'lishuo',
age: 22
}
for (const [key, value] of Object.entries(obj)) {
console.log(`${key}: ${value}`);
}
// name: lishuo
// age: 22
//返回为字符串

generator 函数

generator函数,可以通过 yield 关键字键函数挂起(让函数停留在当前的位置) 为了改变执行流提供了可能,同时为了做异步编程提供了可能

genertor函数没有执行器,需要 next() 方法来调用。 generator函数的返回值是Iterator(迭代器)

1.function后面 函数名之前有一个 * 2.只能在函数内部使用yield表达式,让函数挂起

function* fun(){
console.log(111);//执行第一次
yield 1;//停止 1 为next()方法返回的value
console.log(222);//执行第二次
yield 2;//再次停止
console.log(333);//执行第三次
}
//调用的时候返回一个类似迭代器对象,可以调用next()方法
//generator函数分段执行的,yield是暂停执行,然而next()是恢复执行
var it = fun()//要用第三方变量接函数,不然每一次直接调用都为第一次调用
console.log(it.next());//111 {value: 1, done: false}
console.log(it.next());//222 {value: 2, done: false}
console.log(it.next());//333 {value: undefined, done: true}

//value为yield返回的值 done为函数是否运行结束

调用时利用 next () 传参

    function* fun2() {
console.log("start");
let x = yield '第一次暂停';
console.log("第二个next传递的参数为:" + x);
let y = yield '第二次暂停';
console.log("第三个next传递的参数为::" + y);
}

let it = fun2();
console.log(it.next());//start {value: '第一次暂停', done: false}
console.log(it.next(10));//第二个next传递的参数为:10 {value: '第二次暂停', done: false}
console.log(it.next(30));//第三个next传递的参数为::30 {value: undefined, done: true}



//注意:x 不是 yield 的返回值 next 将参数传递给 yield 后赋给 x

使用场景 :

为不具备Interator接口的对象提供了遍历操作

        // 使用场景 :为不具备Interator接口的对象提供了遍历操作
const obj = {
name: "张三",
age: 10
}
//1.创建新的迭代器
obj[Symbol.iterator] = objectEntries;
//2.搞一个generator函数
function* objectEntries(obj) {
//获取对象所有的key保存到数组[name,age]
const propkeys = Object.keys(obj);//使用keys方法使得obj可以被迭代
for (const propkey of propkeys) {
yield [propkey, obj[propkey]];
}
}
// 迭代器一旦生成我们就可以利用for of进行遍历了
for (let [key, val] of objectEntries(obj)) {
console.log(key, val)
}
// var it = objectEntries(obj);
// console.log(it.next());
// console.log(it.next());
// console.log(it.next());

生成器的应用

        //搞一个生成器主函数main
function* main() {
let res = yield request("https://api.apiopen.top/videoHomeTab");//ajax获取数据
console.log(res);
}

// 调用函数
let it = main();

it.next()

// 封装一个请求接口的函数
function request(url) {
$.ajax({
type: "get",
url: url,
async: true,
success: function (res) {
it.next(res)
}
})
}

生成器AJAX案例

当页面未加载时展示UI 加载完成后展示另一个UI


<body>
<div class="loadUI">
<h1>客观请稍等正在加载数据</h1>
</div>
<div class="content">

</div>
</body>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
// 小案例
// 加载Loading....页面
// 数据加载完成(异步操作)
function* load() {
// 异步代码同步化
loadUI();//页面未加载完成时展示的UI
yield showData();
hideUI();
}
let itLoad = load();
itLoad.next();//执行第一次

function loadUI() {
$(".loadUI").show()
}
function showData() {
$.ajax({
type: "get",
url: "https://api.apiopen.top/videoHomeTab",
async: true,
success(res) {
for (var i = 4; i < res.result.length; i++) {
var id = res.result[i].id;
$.ajax({
type: "get",
url: "https://api.apiopen.top/videoCategoryDetails",
async: true,
data: {
id: id
},
success(res) {
console.log(res)
var data = res.result;
$.each(data, function (indexInArray, valueOfElement) {
let description = valueOfElement.data.content.data.author.description;
let icon = valueOfElement.data.content.data.author.icon;
let str = `
<h3>${description}</h3>
<img src = "${icon}"/>
`
$(".content").append(str);
});
// 执行下一步
itLoad.next();
}
});
}
},


});

}
function hideUI() {
$(".loadUI").hide()
}

// 生成器(generator)的作用:部署ajax操作,可以让异步代码同步化
</script>

async 函数

async 函数实际上就是Generator 函数的语法糖(语法的简易写法)

async 函数就是将 Generator 函数的星号( * )替换成 async ,将 yield 替换成 await ,仅此而已。

 async function fun(){
// var err = new Error('出现错误');
// throw err;
return await "你好 async";
}
var p = fun()
p.then(res=>{
console.log(res);//若没有错误,在此打印
}).catch(err=>{//若出现错误,被catch捕捉
console.log(err);//在此打印错误
})
function timeout(ms) {
return new Promise((resolve) => {//resolve在此处传递的是 Promise是否执行成功
// var err = new Error('运行出现错误')
// throw err;//当出现错误的时候,停止在下端await不继续执行
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);//await 在此做了同步化处理。若没有await使其等待,则会先执行打印
console.log(value);
}
asyncPrint('hello world', 2000);

async 函数内部 return 语句返回的值,会成为 then 方法回调函数的参数。

async 函数内部抛出错误,会导致返回的 Promise 对象变为 reject 状态。抛出的错误对象会被 catch 方法回调函数接收到。

正常情况下, await 命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。 上面代码中, await 命令的参数是数值 "你好 async" ,这时等同于 return "你好 async"

async 函数返回的 Promise 对象,必须等到内部所有 await 命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return 语句或者抛出错误。也就是说,只有 async 函数内部的异步操作执行完,才会执行 then 方法指定的回调函数。`

async 函数对 Generator 函数的改进,体现在以下四点:

内置执行器 Generator函数执行必须靠执行器 next() ,而 async 函数自带执行器。可以像普通函数一样直接调用。

更广的适应性 co 模块约定, yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。

返回值是 Promise 对象 async 函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用 then 方法指定下一步的操作。

进一步说, async 函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而 await 命令就是内部 then 命令的语法糖。

async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇到 await 就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

Class 类

ES5创建构造函数

        function Person(name,age){
this.name = name;//所有被构造函数创建的对象都会有的属性
this.age = age;
}
Person.prototype.say= function(){//通过原型链,可以给所有被创建的对象添加方法
console.log(`你好我是${this.name}`);
}
let xm = new Person("小明",10);
xm.say()
        function Person(name,age){
this.name = name;
this.age = age;
this.say = function(){
console.log(`你好我是${this.name}`);//通过this创建的say方法只是构造函数拥有,构造函数创建的对象不拥有
}
}

let xm = new Person("小明",10);
xm.say()

Es6 通过类创建对象

        class Student {
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(`你好我是${this.name}`);
}
skill(){
console.log(`${this.name}会打乒乓球`);
}
}
let zs = new Student("张三",30)//通过类创建的对象,可以直接使用 say() skill() 方法
let ls = new Student("李四",30)
zs.say();
ls.skill();

ES6 类的继承

使用关键字 extends继承

super 关键字用于访问和调用一个对象的父对象上的函数。

在构造函数中使用时, super 关键字将单独出现,并且必须在使用 this 关键字之前使用。 super 关键字也可以用来调用父对象上的函数。

        class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
say() {
return `你好我是${this.name}`
}
}

class Student extends Person {
constructor(name, age, stId) {
super(name, age);//注意,在派生的类中,使用this前,必须先调用 super() ;这里调用父类的构造函数的,为派生类使用
this.stId = stId;
}
skill() {
console.log(`${this.name}会打乒乓球`);
}
}

let zs = new Person("张三",30);//父类创造的对象
let xm = new Student("小明",10,"12345678")//派生类创造的对象


console.log(zs.say());//父类创造的对象可以使用父类的方法
console.log(xm.say());//派生类创造的对象也可以使用父类的方法
xm.skill();//派生类使用自己的方法

ES5中的继承

1.//原型链继承
实现方式:将子类元素的原型链指向父类继承
function Parent(){
this.name = "parent";
this.list = ['a'];
}
Parent.prototype.sayHi = function(){
console.log('hi');//hi
}
function Child(){

}
Child.prototype = new Parent();
var child = new Child();
console.log(child.name);//parent
child.sayHi();
原理:子类实例child的__proto__指向Child的原型链prototype,而Child.prototype指向Parent类的对象实例,该父类对象实例的__proto__指向Parent.prototype,所以Child可继承Parent的构造函数属性、方法和原型链属性、方法
优点:可继承构造函数的属性,父类构造函数的属性,父类原型的属性
缺点:无法向父类构造函数传参;且所有实例共享父类实例的属性,若父类共有属性为引用类型,一个子类实例更改父类构造函数共有属性时会导致继承的共有属性发生变化;实例如下:
var a = new Child();
var b = new Child();
a.list.push('b');
console.log(b.list); // ['a','b']
2.构造函数继承
实现方式:在子类构造函数中使用call和apply劫持父类构造函数方法,并传入参数
function Parent(name, id){
this.id = id;
this.name = name;
this.printName = function(){
console.log(this.name);
}
}
Parent.prototype.sayName = function(){
console.log(this.name);
};
function Child(name, id){
Parent.call(this, name, id);
// Parent.apply(this, arguments);
}
var child = new Child("jin", "1");
child.printName(); // jin
child.sayName() // Error
原理:使用call或者apply更改子类函数的作用域,使this执行父类构造函数,子类因此可以继承父类共有属性
优点:可解决原型链继承的缺点
缺点:不可继承父类的原型链方法,构造函数不可复用
3.组合继承
原理:综合使用构造函数继承和原型链继承
function Parent(name, id){
this.id = id;
this.name = name;
this.list = ['a'];
this.printName = function(){
console.log(this.name);
}
}
Parent.prototype.sayName = function(){
console.log(this.name);
};
function Child(name, id){
Parent.call(this, name, id);
// Parent.apply(this, arguments);
}
Child.prototype = new Parent();
var child = new Child("jin", "1");
child.printName(); // jin
child.sayName() // jin

var a = new Child();
var b = new Child();
a.list.push('b');
console.log(b.list); // ['a']
优点:可继承父类原型上的属性,且可传参;每个新实例引入的构造函数是私有的
缺点:会执行两次父类的构造函数,消耗较大内存,子类的构造函数会代替原型上的那个父类构造函数
4.原型式继承
原理::类似Object.create,用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象,结果是将子对象的__proto__指向父对象
var parent = {
names: ['a']
}
function copy(object) {
function F() {}
F.prototype = object;
return new F();
}
var child = copy(parent);
console.log(copy(parent))//[[Prototype]]: Object names: ['a']
缺点:共享引用类型
5.寄生式继承:
原理:二次封装原型式继承,并拓展
function createObject(obj) {
var o = copy(obj);
o.getNames = function() {
console.log(this.names);
return this.names;
}
return o;
}
优点:可添加新的属性和方法
6.寄生组合式继承
原理:改进组合继承,利用寄生式继承的思想继承原型
function inheritPrototype(subClass, superClass) {
// 复制一份父类的原型
var p = copy(superClass.prototype);
// 修正构造函数
p.constructor = subClass;
// 设置子类原型
subClass.prototype = p;
}

function Parent(name, id){
this.id = id;
this.name = name;
this.list = ['a'];
this.printName = function(){
console.log(this.name);
}
}
Parent.prototype.sayName = function(){
console.log(this.name);
};
function Child(name, id){
Parent.call(this, name, id);
// Parent.apply(this, arguments);
}
inheritPrototype(Child, Parent);

一个模块就是一个独立的JS文件 ES6的模块功能主要由两个命令构成: esport 暴漏 (抛出) 、 import()

在需要被暴漏的模块中:

let name = "李四";
let age = 10;
let add = (a,b)=>{
return a+b;
}

const content = {
name:"张三",
age:10,
add(a=0,b=0){
return a+b;
}
}

// 暴露(抛出)
export {name,age,add}//
export {content}

在引入模块的文件内: 注意:在引入模块的文件内,script 标签的 type = ‘module’ 不然会报错

//第一种写法
import {content,name} from "./modules/Module1.js";
console.log(name);//李四

//第二种写法
import * as f from './modules/Module1.js'
//任意命名 f , 暴漏的所有数据都在 f 对象内
//引用可以这样写:
console.log(f.name)//李四

注意:需要暴露什么写什么,需要接收什么写什么

ES5 中请求模块用 require

export default

export default 命令,为 模块 指定默认输出。

在需要被暴漏的模块中:

const name ="张三"; 
const age = 18;


const obj = {
name:"大豆"
}
export {name,age,sayName,Person,obj}
export default obj //此为默认输出

在引入模块的文件内:

        import * as f  from './modules/Module2.js'// f 为自定义命名
// console.log(f)
// f 内为 export 暴漏的所有数据
import a from './modules/Module2.js'// a 为自定义命名
console.log(a)
// a 内为默认暴漏的数据

SQL 语句

INSERT INTO user (user_name,user_phone,user_psw) VALUES('康新洋','18220550304','123456')

插入在 user 表中 插入的键为 user_name , user_phone , user_pwd 插入的值为...

    SELECT * FROM `user`
SELECT * FROM user WHERE user_name='苏倩文'
SELECT * FROM `user` WHERE id = 5


select * from user where phone=变量 or email = 变量
select * from user where (phone=变量 or email = 变量 )and password=变量

查询名为 user 的数据库 查询 user 库中 user_name 为 苏倩文 的 查询 user 库中 id 为5 的

DELETE FROM user WHERE id = 6
DELETE FROM user WHERE user_name = '赵阳'

更新 (更改)

UPDATE `user` SET `user_phone` = '18220550308' WHERE user_name='茹小龙'

设置新的手机号 在 user_name 为 如小龙的数据下

Node.js

需要安装Node环境。

在浏览器打开输入 localhost : 端口号 或 IP地址 : 端口号

创建服务器

//引入http模块
const http = require('http')
//此模块为Node.js 内置模块,无需下载

//设置访问域名
const hostname = 'locohost'

//设置端口
const post = 1225


//创建服务
const server = http.createServer((request, response) => {//request 为请求 ; response 为响应
//请求状态
response.statusCode = 200;
//设置请求头
response.setHeader('Content-Type', 'text/plain;charset=utf-8');//此处有编码方式 utf-8
//返回页面的数据
response.end('Hello World')//注意:end()中只能传字符串
//监听端口
}).listen(post,()=>{
console.log(`服务器运行在 http://${hostname}:/${post}`)
})

//运行此文件在 git 中输入 :
//node 文件名
//运行此文件为 node Node_1.js

//服务器代码改变后需要重启服务器才可生效
//运行结束后需要关闭服务器 快捷键 ctrl+c 或 JS中输入代码 process.exit(1);
const http = require('http');
//const mysql = require('mysql');

const server = http.createServer((req, res) => {
res.end('111')
//在此插入

}).listen(1226)
console.log('服务器成功执行')

http 模块中的 end() 方法传回的参数是传回到页面的

与数据库连接

此处为查询操作 if(req.url === "favicon.ico"){return};//阻止重复请求(放在服务器下)

//请求mysql模块
const mysql = require('mysql')
//mysql模块不是内置模块,在git中输入 npm install mysql -- save 下载模块


//创建链接(与sql)
const connection = mysql.createConnection({
//地址
host: 'localhost',
//sql的用户名密码
user: 'root',
password: 'root',
//数据库名
database: 'web2137',
multipleStatements:true // 支持执行多条 sql 语句
})

//链接
connection.connect();

//sql查询语句
let sql = 'select * from user'

//查询
connection.query(sql,(error,result)=>{
if(error){
throw error;
}
console.log(result);
// process.exit(1); //关闭服务器代码
})

//运行此文件前先打开阿帕奇与sql数据库


//运行此文件在 git 中输入 :
//node 文件名
//运行此文件为 node select_node.js

//运行服务器后需要关闭服务器 JS代码为 process.exit(1);
//或在git中 ctrl + c 关闭服务器

在git中输入 npm install mysql -- save 下载模块 mysql (npm为外网) 在git中输入 cnpm install mysql -- save 下载模块 mysql (cnpm为国内网站)

sql 模块中的 end() 方法为结束数据库操作

创建服务器并查询数据库

//引入模块
const http = require('http');
const mysql = require('mysql');

//创建服务器
const server = http.createServer((req, res) => {//req 为请求; res 为响应
//创建数据库链接
const connection = mysql.createConnection({
host: "localhost",//地址
//post: 1225,// 默认端口 可以不用设置
user: "root",
password: "root",
database: "web2137"//数据库名
})
//连接数据库
connection.connect();
//sql 查询代码
const sql = 'SELECT * FROM `user`'
//查询
connection.query(sql, (error, results) => {//参数为 错误 | 数据
if (error) {
throw error;
}
results = JSON.stringify(results);//end()中只能传入字符串,在此将数据转为字符串
//创建请求头
res.setHeader('Content-Type', 'text/plain;charset=utf-8');//res为服务器响应
res.end(results);
})
})
//监听端口
server.listen(1225);//参数还可加一个回调函数
console.log('成功')

在浏览器中打开: 地址 : 端口号 localhost : 1225 或 ip地址 : 端口号 (cmd中查询IP地址代码:ipconfig) 192.168.0.126 : 1225 引入 http 模块才可在浏览器中打开

module.exports 对象是由模块系统创建的。在我们自己写模块的时候,需要在模块最后写好模块接口,声明这个模块对外暴露什么内容,module.exports 提供了暴露接口的方法

var app = {
name: 'app',
version: '1.0.0',
sayName: function(name){
console.log(this.name);
}
}
module.exports = app;//将app暴漏,可以调用模块
//调用方法
var app = require('./app.js');
app.sayName('hello');//hello

封装的db 数据库模块

const mysql = require('mysql');

module.exports = (sql,callback)=>{
const db = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
database : 'web2137'
});
db.connect();
db.query(sql,callback);
db.end();
};

get请求

const http = require('http');
const request = require('request');//需要下载模块

const server = http.createServer((req,res)=>{
const url = "https://v.juhe.cn/toutiao/index?type=caijing&key=c14887fe64c3c92f7cd9507b34e01257";//请求地址
request(url,(err,response,body)=>{//错误,请求,内容
if(!err && response.statusCode == 200){
// console.log(body);
res.setHeader('Content-Type', 'text/plain;charset=utf-8');
res.end(body);
}
})
});
server.listen(3000);
console.log(666);

post 请求

const post = require('request');
const http = require('http');

const server = http.createServer((req,res)=>{
post({
url:'http://v.juhe.cn/toutiao/index',
form:{
type:'yule',
key:"51c6425aff3ff156f7b2f8bac5496a71"
}
},(error,response,body)=>{
if(!error && response.statusCode == 200){
console.log(body);
res.setHeader('Content-Type', 'text/plain;charset=utf-8');
res.end(body);
}
});

});
server.listen(3000);
console.log(666);

get post 综合代码

const http = require("http");
const db = require("./db");//db模块仍然为封装模块

const server = http.createServer((req,res)=>{
//设置允许所有资源跨域的头属性
res.setHeader("Access-Control-Allow-Origin", "*")
// console.log(req.url);
let wdata = udata(req.url);
console.log(wdata.user_name);
// 数据库的链接
let sql = ` SELECT * FROM user WHERE user_name='${wdata.user_name}'`;
db(sql,(err,results)=>{
if(err){
throw err;
}
results = JSON.stringify(results)
res.setHeader('Content-Type', 'text/plain;charset=utf-8')
res.end(results)
})

// 做一个简单的封装 ,哈哈我就把获取过来的数据当字符串处理了
function udata(str) {
// 注意要是有汉字做个简单的解码decodeURI(str)
str = decodeURI(str);
// 1.处理掉?
var dataStr = str.split("?")[1];
// 2.进行一个截取转化成数组
dataStr = dataStr.split("&");
// 3.定义一个新对象存放数据
var data = new Object()
// console.log(dataStr);
// 4.遍历每个数组对象处理成对象的key:val
dataStr.forEach(function(item) {
var it = item.split("=");
data[it[0]] = it[1];
})
return data;
}

})

server.listen(3000)
console.log(666);

post:

const http = require("http");
const db = require("./db");
const querystring = require("querystring");

const server = http.createServer((req,res)=>{
//设置允许所有资源跨域的头属性
res.setHeader("Access-Control-Allow-Origin", "*")

var str = "";
req.on('data',function(data){
str += data; //串联 data 数据
console.log(str);

});
//获取完所有数据后执行req.on(‘end’,function(){})
req.on('end',function(){
let json = querystring.parse(str);
console.log(json);
let sql = `INSERT INTO user (user_name,user_phone,user_pwd) VALUES('${json.user_name}','${json.user_phone}','${json.upassword}')`;
db(sql,(err,results)=>{
if(err){
throw err;
}
results = JSON.stringify(results)
res.setHeader('Content-Type', 'text/plain;charset=utf-8')
res.end(results)
})
})


})

server.listen(3000)
console.log(666);

尝试后发现,数据库的增删改查只是其中的sql语句发生了改变,所以将其余部分做个封装

封装部分

const mysql = require('mysql');

module.exports = (sql,callback)=>{
const db = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
database : 'web2137'
});
db.connect();
db.query(sql,callback);
db.end();
};

引用部分

const http = require('http');
const db = require('./fzmodule');

const server = http.createServer((req,res)=>{
// console.log(req,res);
//阻止多次发送请求
if(req.url == "/favicon.ico"){
return;
}

let sql = 'INSERT INTO user(user_name,user_phone,user_psw) VALUES("康新洋","18220550304","123456")';
db(sql,(err,results)=>{
if(err){
throw err;
}
results = JSON.stringify(results);
res.setHeader('Content-Type', 'text/plain;charset=utf-8');
res.end(results);
});
});
server.listen(3000);
console.log('666');

Express 框架

首先创建一个基础框架,同时参考菜鸟express安装教程与express官网安装教程安装

const express = require('express')//引用express模块(需要下载)
const app = express()//创建express对象
const port = 3000

//路由
app.get('/', (req, res) => {//访问localhost:3000 默认
res.end('123');
})


app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})

Express中 res.json 和res.end 及res.send()

用于快速结束没有任何数据的响应,使用res.end()。 响应中要发送JSON响应,使用res.json()。 响应中要发送数据,使用res.send() ,但要注意header ‘content-type’参数。 如果使用res.end()返回数据非常影响性能。 使用send发送中文数据就不用设置请求头写编码方式了

路由决定了由谁(指定脚本)去响应客户端请求。 在HTTP请求中,我们可以通过路由提取出请求的URL以及GET/POST参数。

const express = require('express')//引用express模块(需要下载)
const app = express()//创建express对象
const port = 3000

//路由
app.get('/', (req, res) => {//访问localhost:3000 默认
let data = {
name:'aaa'
}
// res.end('123');
// res.send(data);
res.json(data);
})

//路由
app.get('/list',(req,res)=>{//访问localhost:3000/list
res.end('list')
})// /list 相当于访问地址

//路由
// 对页面 abcd, abxcd, ab123cd, 等响应 GET 请求
app.get('/ab*cd', function(req, res) {//正则请求
console.log("/ab*cd GET 请求");
res.send('正则匹配');
})

app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})

Express 提供了内置的中间件 express.static 来设置静态文件如:图片, CSS, JavaScript 等。

app.use('/public', express.static('public'));// /public为静态文件的访问路径

get 接口

get接口中res.query为所有传入的数据

const express = require('express');
const app = express();

app.use('/public', express.static('public'));

app.get('/',(req,res)=>{
let data = {
name:'aaa'
}
// res.end('123');
// res.send(data);
res.json(data);
})

app.get('/list',(req,res)=>{
res.end('list');
})

//接口
app.get('/huoqu',(req,res)=>{//接口地址为/huoqu
// let data = req.query
let user_name = req.query.user_name;
let user_psw = req.query.user_psw;

let data = {
user_name:user_name,
user_psw:user_psw
}
res.send(data);
});




app.listen(3000);
console.log(666);

传输网页为

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>

<form action="http://localhost:3000/huoqu" method="get">注意此传输地址
用户名:<input type="text" name="user_name" value="">
密码:<input type="text" name="user_psw" value="">
<input type="submit" value="Submit">
</form>

</body>
</html>

post 接口

post 接口中 res,body 为所有传入的数据

const express = require('express');
const app = express();//初始化express对象

app.use('/public', express.static('public'));//静态文件地址



var bodyParser = require('body-parser');//引入编码模块
// 创建 application/x-www-form-urlencoded 编码解析
var urlencodedParser = bodyParser.urlencoded({ extended: false })
//post接口
app.post('/denglu', urlencodedParser, function (req, res) {

res.send({
code:1,
msg:'登陆成功',
user_name:req.body.user_name,
user_psw:req.body.user_psw
});
// 输出 JSON 格式
// var response = {
// "first_name":req.body.first_name,
// "last_name":req.body.last_name
// };
// console.log(response);
// res.end(JSON.stringify(response));
})
app.listen(3000);
console.log(666);

html部分

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>post请求</title>
</head>
<body>
<form action="http://localhost:3000/denglu" method="post">
姓名:<input type="text" name="user_name" id="">
<br>
密码:<input type="text" name="user_psw" id="">
<br>
<input type="submit" name="Submit" id="" value="提交">
</form>
</body>
</html>
npm install -g nodemon		//安装

nodemon index.js //热启动 index.js
// 解决跨域问题
app.all("/*", function(req, res, next) {
// 跨域处理
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", ' 3.2.1');
res.header("Content-Type", "application/json;charset=utf-8");
next(); // 执行下一个路由
})

放在 app.js 文件内 所有的路由都不会跨域 放在单独的路由文件内,只有该文件内的路由不会跨域

app.use((req, res, next) => {
//设置请求头
res.set({
'Access-Control-Allow-Credentials': true,
'Access-Control-Max-Age': 1728000,
'Access-Control-Allow-Origin': req.headers.origin || '*',
'Access-Control-Allow-Headers': 'X-Requested-With,Content-Type',
'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS',
'Content-Type': 'application/json; charset=utf-8'
})
req.method === 'OPTIONS' ? res.status(204).end() : next()
})

支持get | post请求的接口

//登录接口接收所有请求,支持get post
router.all('/login', function(req, res, next) {
let odata;
if(Object.keys(req.query).length == 0){//判断使用的是什么请求
odata = req.body;//get请求为空时,odata为post请求的数据
}else{
odata = req.query;
}
res.send(odata);
});

验证码发送

新创建的模块 ( maileConfig.js ) 内nodemailer 模块需要下载

// 准备:进入邮箱:设置>账户>POP3/SMTP服务(开启之后记得复制密钥)

//nodemailer.js
const nodemailer = require('nodemailer');//该模块需要下载

//创建一个smtp服务器
const config = {
host: 'smtp.qq.com',
port: 465,
auth: {
user: '1308876449@qq.com',//开发者邮箱
pass: 'xrchxszowsdubabe',//开发者密钥
}
};
// 创建一个SMTP客户端对象
const transporter = nodemailer.createTransport(config);

//发送邮件
module.exports = function (mail){
transporter.sendMail(mail, function(error, info){
if(error) {
return console.log(error);
}
console.log('mail sent:', info.response);
});
};

index.js 接口部分

var express = require('express');//下载express框架
const { send } = require('express/lib/response');
const maileConfig = require("./maileConfig");//自定义模块
const db = require("../db/db");//自定义模块
const LocalStorage = require('node-localstorage').LocalStorage,//下载localstorage模块
localStorage = new LocalStorage('./scratch');//创建localstorage对象

var router = express.Router();//创建router对象(框架内置)

router.use((req, res, next) => { //设置请求头解决跨域

res.set({
'Access-Control-Allow-Credentials': true,
'Access-Control-Max-Age': 1728000,
'Access-Control-Allow-Origin': req.headers.origin || '*',
'Access-Control-Allow-Headers': 'X-Requested-With,Content-Type',
'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS',
'Content-Type': 'application/json; charset=utf-8'
})
req.method === 'OPTIONS' ? res.status(204).end() : next()
})

//默认主页内容接口
router.get('/', function(req, res, next) {
res.send({
title:'express'
});
});

// 发送邮件的接口
router.get('/email', function (req, res, next) {
//保存验证码和邮箱,时间
let student = {};
let email = req.query.email;
let code = createSixNum();
console.log(code);
let time = new Date().getTime();
student.initCode = code;
student.time = time;
student.email = email;
student = JSON.stringify(student);
// 放入缓存中
localStorage.setItem(email,student)

let sql = `select * from student where email= "${email}"`;
db(sql, (err, data) => {
if (data.length) {
res.send({
code: 0,
message: "邮箱已注册"
})
} else {
var mail = {
// 发件人
from: '<1192719918@qq.com>',
// 主题
subject: '验证码',//邮箱主题
// 收件人
to: email,//前台传过来的邮箱
// 邮件内容,HTML格式
text: '用' + code + '作为你的验证码'//发送验证码
};
maileConfig(mail)
res.send({
code: 1,
msg: "发送成功"
})
}
})


// 随机产生六位验证码
function createSixNum() {
var Num = "";
for (var i = 0; i < 6; i++) {
Num += Math.floor(Math.random() * 10);
}
return Num;
}
});


//验证码校验(注册)
router.post("/jiaoyan", (req, res) => {

let obody = req.body;
// 获取缓存
let student = localStorage.getItem(obody.email)
console.log(student);
student = JSON.parse(student);

const registerTime = new Date().getTime()
if (registerTime - student.time >= 5 * 1000 * 60) {
res.send({
code: -1,
msg: '验证码已过期'
})
}

// console.log(student);
// console.log(obody);
if (student.initCode === obody.code) {
let sql = `INSERT INTO student (name,email,password) VALUES('${obody.name}','${obody.email}','${obody.password}')`;
db(sql,(err,data)=>{

res.send({
code: 1,
message: "注册成功",
data:data
})
})
// 注册成功删除缓存
localStorage.removeItem(obody.email);
console.log("----------------------");
console.log(localStorage.getItem(obody.email));
console.log("----------------------");

}
else {
res.send({
code: 0,
message: "验证码输入错误"
})

}

})

module.exports = router;

查看vue.js 的版本——vue -V (注意后面的V是大写的,需要安装完cue-cli脚手架之后才能查看的到) 安装最新vue.js——npm install vue g

创建项目步骤时的操作: 第一步:Project name: 项目的名称(项目名不能大写) 第二步:Project description:项目的描述 第三步:Author:项目的作者(会自动生成到package.json文件里) 第四步:Vue build:这里有两个选项,第一个选项是运行时编译,可以不基于.vue开发,第二个选项是基于.vue开发比第一个小6kb(选择打包方式,有两种方式(runtime和standalone),使用默认即可) 第五步:install vue-router:是否安装路由中间件 第六步:是否需要ES6代码风格检查器(eslint检测规则) 选择YSE之后,有三个选项,第一个标准的(选择标准的直接回车即可) (是否为严格模式,选no) 第七步:是否需要测试相关(单元测试) 第八步:也是测试相关(e2e测试)

Router(路由模块)

mode : (类型) 默认值:" hash " ( 浏览器环境 ) | " abstract " ( Node.js 环境 ) 可选值:" hash " | " history " | " abstract "

匹配路由环境: hash : 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History Api 的浏览器。 history : 依赖 HTML5 History API 和服务器配置 (下面介绍 HTML5 History 模式) abstract : 支持所有 JavaScript 运行环境,如 Node.js 服务器端。 如果发现没有浏览器的 API,路由会自动强制进入这个模式。

HTML5 History 模式 vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。

如果不想要很丑的 hash,我们可以用路由的 history 模式 ,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。

const router = new VueRouter({
 mode: 'history',
 routes: [...]
})

当你使用 history 模式时,URL 就像正常的 url,例如 http://yoursite.com/user/id ,也好看!

不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404,这就不好看了。

所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。

cli - 去除井号

在 src 的 router 的 index.js 中

import Vue from 'vue'
import Router from 'vue-router'
import father from '@/components/father'

Vue.use(Router)

export default new Router({
mode:'history',//添加此句去除 #
routes: [
{
path: '/',
name: 'father',
component: father
}
]
})

cli 组件的引入

先在 script 中引入需要的组件 再声明组件后便可以使用了

<template>
<div>
<h1>这是父级组件</h1>
<son/><!-- 在此使用组件 -->
</div>
</template>

<script>
import son from './son.vue'//在此引入组件
export default {
name:'father',
components:{//在此声明组件
'son':son,
}
}
</script>


<style scoped>

</style>

router-view 的使用

<router-view/> 可以视为一个载体,显示当前的路由

<template>
<div id="app">
<router-view/> <!-- 在此处显示路由 -->
</div>
</template>

<script>
export default {
name: 'App'
}
</script>

<style>

</style>

Vue 简介

Vue 只关注视图层, 采用自底向上增量开发的设计。 Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与 现代化的工具链 以及各种 支持类库 结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

数据驱动(MVVM)

MVVM 表示的是 Model-View-ViewModel`

Model : 模型层,负责处理业务逻辑以及和服务器端进行交互 View : 视图层,负责将数据模型转化为UI展示出来,可以简单的理解为HTML页面 ViewModel : 视图模型层,用来连接 Model 和 View ,是 Model 和 View 之间的通信桥梁

Vue CDN

<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>

Vue 对象

Vue 对象 接下来的改动全部在以上指定的 le: div 内,div 外部不受影响。

vue 对象内的 this 指向这个vue对象

<script type="text/javascript">
var vm = new Vue({
el: '#vue_det',//此vue对象控制此节点
data: {//用于定义属性
site: "菜鸟教程",
url: "www.runoob.com",
alexa: "10000"
},
methods: {//此内为函数
details: function() {
return this.site + " - 学的不仅是技术,更是梦想!";
}
}
})
</script>

{{ }} 操作文本

数据绑定最常见的形式就是使用 {{...}}(双大括号)的文本插值:

<body>
<div id="app">
{{haha}}
<p>
{{message}}
</p>
</div>
</body>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
haha:"你好",
message:"出了吗"
}
})
</script>

设置获取自定义属性

<div class="left ggbox" v-on:click="myclick" data-index="1">
methods: {
myclick(e){
console.log(e.target.getAttribute('data-index'))
}
},

v- 指令

v-text / v-html

v-text 不识别标签 {{ }} 同样不识别标签

<body>
<div class="vue1">
<p>
{{msg3}}
</p>
<p v-html='msg3'></p>//内添加一个标签
<p v-text='msg3'></p>
</div>
</body>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script>
let vm = new Vue({
el:'.vue1',
data:{
msg3:'<h1>我是第三条信息</h1>',
}
})

</script>

v-on 绑定事件

<body>
<div class="vue1">
<button v-on:click='function1'>点击切换</button>
</div>
</body>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script>
let vm = new Vue({
el:'.vue1',
data:{
msg1:'我是第一条信息',
flag:true,
},
methods: {
function1(){
console.log('这是点击后打印的内容')
}
},
})
</script>

简写形式 @

<body>
<div class="vue1">
<button @:click='function1'>点击切换</button>
</div>
</body>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script>
let vm = new Vue({
el:'.vue1',
data:{
msg1:'我是第一条信息',
flag:true,
},
methods: {
function1(){
console.log('这是点击后打印的内容')
}
},
})
</script>

v-if v-show 隐藏

<body>
<div id="app">
<p v-if="flag">
我是v-if
</p>
<p v-show="flag">
我是v-show
</p>
<button v-on:click="myclick">点我隐藏/显示</button>
</div>
</body>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
flag:true
},
methods: {
myclick(){
this.flag = !this.flag
}
},
})
</script>

两者区别:(本质)

v-if 是动态向DOM树添加或删除DOM元素 v-show 是更改标签的css样式 display设置为none

编译区别:

v-if 切换有一个局部编译 / 卸载的过程,切换过程中适合销毁和重建内部的事件监听和子组件 v-show 就是在控制css

编译条件:

v-if 初始值为false,就不会编译了 v-show 都会编译,初始值为false,只是将dispaly设为none,但它也编译了

因为 v-if 不断在销毁创建,v-show只编译一次,所以v-show性能更好

v-if 更灵活 如果你的页面不想让其他程序员看到就用v-if,它不会在页面中显示。

v-bind 控制属性

<body>
<div id="app">
<a v-bind:href="url">{{msg}}</a>
</div>
</body>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
url:"https://www.baidu.com/",
},
})
</script>

简写形式: :

<body>
<div id="app">
{{msg}}
<a v-bind:href="url">{{msg}}</a>
<!-- 简写 -->
<a :href="url">{{msg}}</a>
<img :src="imgs" alt="">
<input type="button" value="切换" v-on:click="qiehuan">
</div>
</body>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
msg:"哈哈",
url:"https://www.baidu.com/",
imgs:"./dy.jpg"
},
methods: {
qiehuan(){
this.imgs = "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"
}
},
})
</script>

v-for 遍历对象、数组

v-for 遍历时必须添加唯一属性 key

遍历数组 指令语法: v-for = " 数组的每一项 in 数组 " v-for= " item in students " v-for = ' ( v , index ) in 数组 ' v为数组中的每一项 index为下标

遍历对象 指令语法: v-for = " ( v , k ) in person " v为对象属性的值 k为对象属性的值 person为对象名

<body>
<div id="app">
<ol>
<li v-for="item in students">
姓名:{{item.name}}
年龄:{{item.age}}
性别:{{item.sex}}
</li>
</ol>
<p v-for="(v,k) in person">
{{k}}:{{v}}
</p>
</div>
</body>
<script src="./vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
students:[
{
name:"小明",
age:10,
sex:"男"
},
{
name:"小红",
age:10,
sex:"男"
},
{
name:"小王",
age:10,
sex:"男"
}

],
person:{
name:"张三",
waihao:"法外狂徒"
}
}
})
</script>

循环的嵌套

<body>
<div id="app">
<ul>
<li v-for="student in students">
<span v-for="(v,k) in student">
{{k}}:{{v}}
</span>
</li>
</ul>
</div>
</body>
<script src="./vue.js"></script>
<script>
var vm = new Vue({
el:"#app",
data() {
return {
students:[
{
name:"小明",
age:10,
sex:"男"
},
{
name:"小红",
age:10,
sex:"男"
},
{
name:"小王",
age:10,
sex:"男"
}
]
}
},
})
</script>

控制语句 v-if

<body>
<div id="app">
<input type="checkbox" v-model="t" check="t" >
<div v-if="t">
{{ms}}
</div>
<div v-else>
信息不存在
</div>
<div v-if="2>1">
哈哈
</div>
</div>
</body>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el:"#app",
data() {
return {
ms : "123",
t:false
}
},
})
</script>

v-if 用法之一 条件渲染

<body>
<div id="app">

<div v-if="students.length">
{{students}}
</div>
<div v-else>
没有同学
</div>

</div>
</body>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: "#app",
data() {
return {
students: [
{
name: "小明",
age: 10,
sex: "男"
},
{
name: "小红",
age: 10,
sex: "男"
},
{
name: "小王",
age: 10,
sex: "男"
},
{
name: "狗蛋",
age: 10,
sex: "男"
}
]
}
},
})
</script>

不识别vue语法 v-pre

<body>
<div id="app">
<p v-pre><!-- 不识别vue的语法,只当作正常的字符输出 -->
{{ms}}
</p>
<p>
{{ms}}
</p>
</div>
</body>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el:"#app",
data() {
return {
ms : "123",
t:false
}
},
})
</script>

优化vue加载 v-cloak

注意:使用 v-cloak 时,vue的引入必须在css前,因为vue语句在css中用到了

    <script src="./vue.js"></script>
<style>
[v-cloak]{

display: none;

}
</style>
</head>
<body>
<div id="app">

<p v-cloak>
{{ms2}}
</p>
<p>
{{ms}}
</p>
<p>
{{ms}}
</p>
<p>
{{ms}}
</p>
</div>
</body>
<script>
const vm = new Vue({
el:"#app",
data() {
return {
ms : "123",
ms2 : "你好帅",
t:false
}
},
})
</script>

双向绑定 v-model

<body>
<div id="app">
<input type="text" v-model="ms">
<input type="checkbox" v-model="t" check="t">
<p>
{{ms}}
</p>
<p>
{{t}}
</p>
</div>
</body>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el:"#app",
data() {
return {
ms : "123",
t:false
}
},
})
</script>

vue属性

方法属性 method

在method中存放被调用的方法

计算器属性 computed

我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,相关依赖发生改变时才会重新取值 。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。

计算中,相关依赖发生变化时就会重新运行 直接当做普通属性调用不加括号 任何data中数据变化立即重新计算 计算属性会缓存

举例:购物车的结算功能

<script src="./vue.js"></script>
<body>
<div id="app">
<p>{{msg}}</p>
<p>{{fanzhuan}}</p>
<input type="text" v-model='msg'>
</div>
</body>
<script>
const vm = new Vue({
el:"#app",
data:{
msg:"abcd"
},
computed:{
fanzhuan(){
let res = this.msg.split("").reverse().join("")
return res;
}
}
})
</script>

模板属性template

模板必须设置 type , id

<body>

<div id="app">

</div>
</body>
<!-- 模板必须要设置type,还要设置id -->
<script type="x-template" id="box">
<div>
hello:{{msg}}
</div>
</script>

<script>
var vm = new Vue({
el:"#app",
data:{
msg:"哈哈"
},
template:"#box"
})

</script>

vue中 template 标签的妙用

需求: div v-for 做了列表循环,现在想要 span 也一起循环

<div id="app">
<div>
<div v-for='(item,index) in list' :key='item.id'>{{item.id}}--{{index}}</div>
<span>{{item.text}}</span>
</div>
</div>

利用 template 标签解决

 <div id="app">
<template v-for="(item, index) in list" :key="item.id">
<div>{{item.text}}--{{index}}</div>
<span>{{item.text}}</span>
</template>
</div>

template的作用是模板占位符,可帮助我们包裹元素,但在循环过程当中,template不会被渲染到页面上

组件component

vue组件定义 1.组件(Component)是Vue.js最强大的功能之一 2.组件可以扩展HTML元素,封装可重用代码 3.在较高层面上,组件是自定义元素,Vue.js的编译器为他添加特殊功能 4.某些情况下,组件也可以表现用 js 特性进行了扩展的原生的HTML元素 5.所有的Vue组件同时也都是Vue实例,所以可以接受 相同的选项对象(除了一些根级特有的选项),并提供 相同的生命周期钩子函数

vue组件的功能

能够把页面抽象成多个相对独立的模块

实现代码重用,提高开发效率和代码质量,使得代码易于维护

Vue组件封装过程 1.首先,使用Vue.extend()创建一个组件 2.然后,使用Vue.component()方法注册组件 3.接着,如果子组件需要数据,可以在props中接收定义 4.最后,子组件修改好数据之后,想把数据传递给父组件,可以使用emit()方法

创建组件的三个方法

一:js当中创建组件

<body>
<div id="app">
<haha></haha>
<haha></haha>
<haha></haha>
</div>
</body>
<script>
// 创建组件
var haha = Vue.extend({
template:`<h1>哈哈</h1>`
})

var vm = new Vue({
el:"#app",
// 注册组件
components:{
"haha":haha//值为创建的组件,键为标签名
}

})
</script>

二:pemplate 标签中创建组件

<body>
<div id="app">
<top></top>
<top></top>
<top></top>
</div>
<!-- 组件模板 -->
<template id="top">
<div>
<h1>我是组件</h1>
</div>
</template>
</body>

<script>

var vm = new Vue({
el:"#app",
// 注册组件
components:{
"top":{
template:"#top"
}
}

})
</script>

三:在新的 script 中创建组件

<body>
<div id="app">
<top></top>
<top></top>
<top></top>
</div>

</body>

<script type="text/x-template" id="top">
<div>我是一个组件</div>
</script>

<script>
var vm = new Vue({
el:"#app",
// 注册组件
components:{
"top":{
template:"#top"
}
}
})
</script>

展示多个组件

<body>    
<div id="app">
<haha></haha>
<contents></contents>
</div>

</body>
<script src="vue.js"></script>
<script>
// 写两个组件
var header = {
template:`
<div>哈哈我是头部</div>
`
}
var contents = {
template:`
<div>这是主页内容</div>
`
}
var vm = new Vue({
el:"#app",
// 注册多个组件
components:{
"haha":header,
"contents":contents
}
})
</script>

局部注册组件

<body>
<div id="app1"><!-- 组件在app1中被注册 -->
<haha></haha>
</div>

<div id="app2"><!-- 组件在app2中没有被注册,故不能使用 -->
<!-- <haha></haha> -->
</div>

<!-- 模板 -->
<template id="haha">
<div>
这是头部组件
</div>
</template>
</body>
<script>
// 注册局部组件
var vm1 = new Vue({
el:"#app1",
components:{
haha:{
template:"#haha"
}
}

})

var vm2 = new Vue({
el:"#app2"
})
</script>

<component> </component> 标签是Vue框架自定义的标签,它的用途就是可以动态绑定我们的组件,根据数据的不同更换不同的组件

用法:渲染一个"元组件"为动态组件。依 is 的值,来决定哪个组件被渲染

<body>
<!-- 让多个组件使用同一个挂载点,并动态切换,这就是动态组件 -->
<div id="app">
<input type="button" value="第一个组件" @click="aa='hello'">
<input type="button" value="第二个组件" @click="aa='world'">
<component :is="aa"></component><!-- is 确定哪个组件被渲染 -->
<hello></hello>
<world></world>
</div>
</body>
<script>
let vm = new Vue({
el: "#app",
data: {
msg: "水电费水电费",
aa: "hello",// hello 为下面组件注册的组件
},
components: {
'hello': {
template: '<h1>我是hello组件</h1>'
},
'world': {
template: '<h1>我是world组件</h1>'
},
},
})
</script>

注册全局组件

<body>
<div id="app1">
<haha></haha>
</div>

<div id="app2">
<haha></haha>
</div>


</body>
<script>
// 注册全局组件
Vue.component("haha",{
template:`<div>哈哈我是一个组件</div>`
})

var vm1 = new Vue({
el:"#app1",

})

var vm2 = new Vue({
el:"#app2"
})
</script>

prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。

父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":

<body>
<div id="app">
<haha :message="msg" :id="1"></haha><!-- 传值 -->
</div>
</body>
<script>
Vue.component('haha',{
props: ['message',"id"],//需要传的键为message、id
template:'<div>{{message}} ----- {{id}}</div>'
})

var vm = new Vue({
el:"#app",
data:{
msg:"你好我来了",
}
})
</script>

自定义属性

注意:自定义属性放在在实例化vue对象前 需要给Vue对象

<body>
<div id="app">
<div v-background v-border>
{{name}}
</div>
</div>
</body>
<script>
// 自定义属性
Vue.directive('background', {
bind: function(el) {
el.style.background = "red";
}
})
Vue.directive('border',{
bind:function(el){
// border: 3px solid green;
el.style.border = " 3px solid green";
}
})
let vm = new Vue({
el: "#app",
data: {
name: "张三",
},
})
</script>
<body>
<div id="app">
{{msg}}
<button @click = "btn">更新</button>
<button @click = "xiaohui">销毁</button>
</div>

</body>
<script>
new Vue({
el:"#app",
data:{
msg:"哈哈"
},
methods: {
btn(){
this.msg = "2222"
},
xiaohui(){
this.$destroy();
}
},
beforeCreate() {
alert("马山开始")
},
created() {
alert("创建完成")
},
beforeMount() {
alert("开始挂载")
},
mounted() {
alert("挂载完成")
},
beforeUpdate() {
alert("马上更新")
},
updated() {
alert("更新完成")
},
// 7.销毁之前
beforeDestroy() {
alert("销毁前");
},
// 8.销毁之后
destroyed() {
alert("销毁完成")
},
})
</script>

监听与深度监听

使用 vm.$watch ( ' 监听的数据 ' , function ( ) { } ) 来监听

监听的数据发生变化,则会调用回调函数

监听只能监听data中的普通数据 不能监听data中的对象

<body>
<div id="app">
<p>{{name}}</p>
<p>{{student}}</p>
<button @click = "btn">变一下</button>
</div>
</body>
<script>
let vm = new Vue({
el: "#app",
data: {
name: "小明",
student:{
name: "张三",
}
},
methods: {
btn(){
this.name = "狗蛋"
}
},
})

vm.$watch('name', function () {//当 name 发生变化时,回调函数被调用
alert("name发生了变化");
})

</script>

而深度监听可以监听 data 中的对象 使用 vm.$watch ( '被监听的对象' , function () {} , { deep:true } ) 来监听

<body>
<div id="app">
<p>{{name}}</p>
<p>{{student}}</p>
<button @click = "btn">变一下</button>
</div>
</body>
<script>
let vm = new Vue({
el: "#app",
data: {
name: "小明",
student:{
name: "张三",
}
},
methods: {
btn(){
this.student.name = "狗蛋"
}
},
})
// 监听对象的时候需要深度监听
vm.$watch('student', function () {
alert("student发生了变化");
},{
deep:true
})

</script>

Vue.filter ( ' 过滤的变量 ' , function ( val ){ return } ) 来过滤

过滤器设置后会自动执行

过滤器必须有 return (过滤器中存在判断,return需要在判断外)

<body>
<div id="app">
{{ shuzi | a}}<!-- 满足过滤条件渲染 a 不满足条件渲染 shuzi -->
</div>
</body>
<script>
// 过滤器
Vue.filter('a', function(val) {//val 获取的是 shuzi
if(val < 10 ){
val = '0' + val
}
return val
// return val < 10 ? '0' + val : val;//简写形式
})

let vm = new Vue({
el: "#app",
data: {
shuzi: 5
},
})

</script>

过滤器实例: 时间过滤器

<body>
<div id="app">
{{ dateTime | date }}
</div>
</body>
<script>
Vue.filter('date', function(val) {
let oTime = new Date(val);
return oTime.getFullYear() + '-' +((oTime.getMonth() + 1) < 10 ? '0'+(oTime.getMonth() + 1):(oTime.getMonth() + 1)) +'月'+ '星期' + oTime.getDay() + ' ' +(oTime.getHours() < 10 ? '0'+oTime.getHours():oTime.getHours()) + ':' + (oTime.getMinutes()<10?'0'+oTime.getMinutes():oTime.getMinutes()) + ':' + (oTime.getSeconds()<10?'0'+oTime.getSeconds():oTime.getSeconds());
})
let vm = new Vue({
el: "#app",
data: {
dateTime: Date.now()
},
created() {
let a = setInterval(() => {
this.dateTime = Date.now()
}, 1000);
},
})
</script>

Vue 自带服务器,服务器之间不会跨域,所以要配置代理,可以避免跨域

Axios 是一个基于 Promise 的 HTTP 库,可以用在浏览器和 node.js 中。

axios 使用前需要引入

npm install --save axios vue-axios

将以下代码按顺序引入到入口文件中 routers > index.js

import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.use(VueAxios, axios)

按照以下方式进行使用:

Vue.axios.get("api")
.then((response) => {//获取数据
console.log(response.data)
})
.catch(function(err){//错误捕捉
console.log(err)''
})

this.axios.get(api).then((response) => {
console.log(response.data)
})

this.$http.get(api).then((response) => {
console.log(response.data)
})

传递参数:

axios.get("api", {//get请求
params: {//传递的参数
type: '参数1',
key: "参数2",
},
})
.then((response) => {//获取数据
console.log(response);
})
.catch((err) => {//错误捕捉
console.log(err);
throw err;
});
},

axios cdn:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>

跨域处理(设置代理)

当api存在跨域时,在 config 文件中的 index.js 文件中设置代理 proxyTable 对象内写代理

proxyTable: {
'/api': {//代理1
target: 'http://v.juhe.cn',//后端接口地址
changeOrigin: true,//是否允许跨越
pathRewrite: {
'^/api': '',//重写,
}
},
//代理2.3...
},

原接口地址为 http://v.juhe.cn/toutiao/index 代理将 http://v.juhe.cn 用 /api 代替

axios 使用时写法为:

axios.get("/api/toutiao/index", {//注意:/api 代替的是 http://v.juhe.cn
params: {//传递的数据
type: that.type,
key: "3ce4c1aa53b9069b223b3d3b193975ff",
},
})
.then((response) => {//成功获取的数据
console.log(response);
})
.catch((err) => {//错误捕捉
console.log(err);
throw err;
});
},

页面组件间传值

this . $router . push ( ' /son ' ) 跳转页面

<router-link :to="'home'"> Home </router-link> 跳转页面 (v-bind)

<!-- 字符串 -->
<router-link to="home">Home</router-link>
<!-- 渲染结果 -->
<a href="home">Home</a>

<!-- 使用 v-bind 的 JS 表达式 -->
<router-link v-bind:to="'home'">Home</router-link>

<!-- 不写 v-bind 也可以,就像绑定别的属性一样 -->
<router-link :to="'home'">Home</router-link>

<!-- 同上 -->
<router-link :to="{ path: 'home' }">Home</router-link>

<!-- 命名的路由 -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>

<!-- 带查询参数,下面的结果为 /register?plan=private -->
<router-link :to="{ path: 'register', query: { plan: 'private' }}"
>Register</router-link

this.$router.push({path: "/son",query: {'msg': this.msg},}); 携带参数跳转

举例: 跳转前传参的页面

<template>
<div>
<h1>这是父级组件</h1>
<son />
<button @click="btn">点击携带数据跳转到下一个页面</button>
</div>
</template>

<script>
import son from "./son.vue";

export default {
name: "father",
data() {
return {
msg: "我是被传送的数据",
};
},
components: {
son: son,
},
methods: {
btn() {
this.$router.push({ // 携带参数跳转
path: "/son", //跳转的地址
query: { //携带的参数
'msg': this.msg,
},
});
},
},
};
</script>


<style scoped>
</style>

接收参数的页面:

<template>
<div>
<h1>这是子级组件</h1>
{{msg}}
</div>
</template>

<script>
export default {
name: "son",
data(){
return{
msg:''
}
},
created() {
console.log(this.$route.query)//接收参数
this.msg = this.$route.query.msg;
},
};
</script>


<style scoped>
</style>

父组件传值给子组件

使用子组件时将值传递给子组件

<template>
<div>
<div>AAA</div>
<bbb :msg="msg" /><!-- 在此使用子组件,并且将名为 msg 的数据传递给子组件 -->
</div>
</template>
<script>
import bbb from "./BBB.vue";//在此引入子组件
export default {
name: "AAA",
data(){
return{
msg:"我是父组件的msg"
}
},
components: {//声明组件
bbb: bbb,
},
};
</script>
<style scoped>
</style>

子组件利用 props 接收数据

prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":

<template>
<div>
BBB
{{msg}}
</div>
</template>
<script>
export default {
props:['msg'],//子组件在此接收数据
}
</script>
<style scoped>

</style>

子组件传值给父组件

子组件 : 利用 this . $emit ( " change " , this.msgs ) 传递数据 子组件:

<template>
<div>
BBB
<button @click="shuchu">输出数据给父组件</button>
</div>
</template>

<script>
export default {
data(){
return{
msgs:'这是子组件中的值'
}
},
methods:{
shuchu(){
//this.$emit("命名的事件",传递的数据)
this.$emit("change",this.msgs)
},
},
}
</script>
<style scoped>

</style>

父组件: @change="con" con(d){}

<template>
<div>
<div>{{msgs}}</div>
<bbb @change="con" /><!-- 在此使用子组件,并且绑定子组件定义的事件名, 事件内容为con -->
</div>
</template>
<script>
import bbb from "./BBB.vue";
export default {
name: "AAA",
data(){
return{
msgf:"我是父组件的msg",
msgs:''

}
},
components: {
bbb: bbb,
},
methods:{
con(d){//d为子组件传入的数据
console.log(d)//打印从子组件获得的数据
this.msgs = d
}
},
};
</script>
<style scoped>
</style>

兄弟组件间的传值

1.创建一个公共的 bus.js 文件 (实例化 vue 对象)

import Vue from 'vue'
export default new Vue()

2.组件 A 的代码块:

<template>
<div>
AAAAAAA
<button @click="btn">走起</button>
</div>
</template>
<script>
import bus from './bus'//引入公共组件
export default {
data() {
return {
aStr:"A中的数据"
}
},
methods:{
btn(){
bus.$emit("change",this.aStr)//将值传入至公共组件中 (注意:这是对 bus 的操作)
}
}
}
</script>

3.组件 B 中的代码块:

<template>
<div>
BBBBBB{{bstr}}
</div>
</template>
<script>
import bus from './bus' //同样引入公共组件

export default {
data() {
return {

}
},
computed:{

bstr(){
bus.$on("change",function(d){//给公共组件绑定事件,来获取数据(注意,这是对 bus 的操作)
console.log(d);

})
}
}

}
</script>

无关组件传值(事件总线)

1.在main.js中

Vue.prototype.$bus = new Vue()	//$bus是原型对象上的实例

2.在传递参数的组件中

methods:{
chuandi(){
this.$bus.$emit("busfunction",this.name)
},
}

3.在接收参数的组件中( 在生命周期钩子中 )

mounted() {
this.$bus.$on("busfunction", (a) => {
//do something
});
},

4.在接受参数的组件中(在生命周期钩子中)

使用$bus的时候在接受bus的组件中别忘了再beforDestroy函数中销毁bus,不销毁的话会一直叠加的调用这个方法

beforeDestroy() {
this.$bus.$off("busfunction");
},

Vue X

Vuex 是一个专为 Vue.js 应用程序开发的 状态管理模式 。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

试想一下,如果在一个项目开发中频繁的使用组件传参的方式来同步data中的值,一旦项目变得很庞大,管理和维护这些值将是相当棘手的工作。为此,Vue为这些被多个组件频繁使用的值提供了一个统一管理的工具——VueX。在具有VueX的Vue项目中,我们只需要把这些值定义在VueX中,即可在整个Vue项目的组件中使用。

Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。

安装(其余安装方式在官网) npm install vuex --save

在项目的根目录下新增一个 store 文件夹 在文件夹内创建 index.js 此时的项目 src 文件夹内应当为:

│  App.vue(跟文件)
│ main.js(入口文件)

├─assets(图片)
│ logo.png

├─components(组件)
│ HelloWorld.vue

├─router(接口)
│ index.js

└─store(vuex 仓库)
index.js

初始化 store 下的 index.js 中的 vuex

import Vue from 'vue'
import Vuex from 'vuex'//引入vuex

//挂载Vuex
Vue.use(Vuex)

//创建VueX对象
const store = new Vuex.Store({
state:{//state 属性 存放的键值对就是所要管理的状态
name:'helloVueX'
}
})

export default store //暴露抛出

将 store 挂载到当前项目的 Vue 实例中 main.js

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store, //store:store 和router一样,将我们创建的Vuex实例挂载到这个vue实例中
render: h => h(App)
})

在各个组件中使用: {{ $store.state.name }} $store 指向 Vuex 对象

<template>
<div id='app'>
name:
<h1>{{ $store.state.name }}</h1>
</div>
</template>

在组件的方法中使用: this.$store.state.name this 指向Vue $store 指向Vuex


methods:{
add(){
console.log(this.$store.state.name)
}
},

注意,请不要在此处更改 state 中的状态的值,后文中将会说明

Vuex 的五大属性

state 存放状态 当mutation修改了state的数据的时候,他会动态的去修改所有的调用这个变量的所有组件里面的值( 若是store中的数据发生改变,依赖这个数据的组件也会发生更新 )

mutations state 成员操作 mutations 是操作 state 数据的方法的集合,比如对该数据的修改、增加、删除等等。 mutations 方法都有默认的形参:( [state] [,payload] )

state 是当前 VueX 对象中的 state

payload 是该方法在被调用时传递参数使用的

例如,我们编写一个方法,当被执行时,能把下例中的name值修改为 "jack" ,我们只需要这样做

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.store({
state:{
name:'helloVueX'
},
mutations:{
//es6语法,等同edit:funcion(){...}
edit(state){
state.name = 'jack'
}
}
})

export default store

而在组件中,需要这样去调用这个 mutation ——例如在App.vue的某个 method 中:

this.$store.commit('edit')
//this 指向vue; $store 指向 vuex; commit()提交函数(函数名)

Mutation 传值

单个值提交时:

this.$store.commit('edit',15)

当需要多个参数提交时,将他们放在一个对象中来提交:

this.$store.commit('edit',{age:15,sex:'男'})

接收挂载的参数:

        edit(state,payload){
state.name = 'jack'
console.log(payload) // 15或{age:15,sex:'男'}
}

另一种提交方式:

this.$store.commit({
type:'edit',
payload:{
age:15,
sex:'男'
}
})

增删 state 中的成员: (在store 的 index.js 的方法中) 为了配合Vue的响应式数据,我们在Mutations的方法中,应当使用Vue提供的方法来进行操作。如果使用 delete 或者 xx.xx = xx 的形式去删或增,则Vue不能对数据进行实时响应。 Vue.set 为某个对象设置成员的值,若不存在则新增

Vue.set(state,"age",15)

Vue.delete 删除成员:

Vue.delete(state,'age')
getters:{
nameInfo(state){
return "姓名:"+state.name
},
fullInfo(state,getters){
return getters.nameInfo+'年龄:'+state.age
}
}

组件中调用:

<p>{{$store.getters.nameInfo}}</p>

在组件的 methods 中调用:

this.$store.getters.fullInfo

actions 异步操作

由于直接在 mutation 方法中进行异步操作,将会引起数据失效。所以提供了Actions来专门进行异步操作,最终提交 mutation 方法。 Actions 中的方法有两个默认参数

context 上下文(相当于箭头函数中的this)对象

payload 挂载参数

我们在两秒中后执行 2 节中的 edit`方法

由于 setTimeout 是异步操作,所以需要使用 actions

actions:{
aEdit(context,payload){
setTimeout(()=>{
context.commit('edit',payload)
},2000)
}
}

在组件中调用:

this.$store.dispatch('aEdit',{age:15})

由于是异步操作,所以我们可以为我们的异步操作封装为一个 Promise 对象

    aEdit(context,payload){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
context.commit('edit',payload)
resolve()
},2000)
})
}

modules 模块化状态管理

当项目庞大,状态非常多时,可以采用模块化管理模式。Vuex 允许我们将 store 分割成 模块(module) 。每个模块拥有自己的 state、mutation、action、getter 、甚至是嵌套子模块——从上至下进行同样方式的分割。

modules:{
a:{
state:{},
getters:{},
....
}
}

组件内调用模块a的状态:

this.$store.state.a

而提交或者 dispatch 某个方法和以前一样,会自动执行所有模块内的对应 type 的方法:

this.$store.commit('editKey')
this.$store.dispatch('aEditKey')

模块的细节:

模块中 mutations getters 中的方法接受的第一个参数是自身局部模块内部的 state

modules:{
a:{
state:{key:5},
mutations:{
editKey(state){
state.key = 9
}
},
....
}
}

getters 中方法的第三个参数是根节点状态

modules:{
a:{
state:{key:5},
getters:{
getKeyCount(state,getter,rootState){
return rootState.key + state.key
}
},
....
}
}

actions 中方法获取局部模块状态是 context.state ,根节点状态是 context.rootState

modules:{
a:{
state:{key:5},
actions:{
aEidtKey(context){
if(context.state.key === context.rootState.key){
context.commit('editKey')
}
}
},
....
}
}

规范目录结构

如果把整个 store 都放在 index.js 中是不合理的,所以需要拆分。比较合适的目录格式如下:

store:.
│ actions.js
│ getters.js
│ index.js
│ mutations.js
│ mutations_type.js ##该项为存放mutaions方法常量的文件,按需要可加入

└─modules
Astore.js

对应的内容存放在对应的文件中,和以前一样,在 index.js 中存放并导出 store state 中的数据尽量放在 index.js 中。而 modules 中的 Astore 局部模块状态如果多的话也可以进行细分。

修改一:build > utils.js (修改publicPath:"../../" , 这样写是处理打包后找不到静态文件的问题)

    // Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader',
publicPath: '../../' //这里是要添加的代码
})
} else {
return ['vue-style-loader'].concat(loaders)
}

修改二:config > index.js (修改assetsPublicPath:'./' ,修改目的是为了解决js找不到的问题)

 build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),

// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: './', // 在这里修改

/**
* Source Maps
*/

productionSourceMap: true,

然后执行 npm run build 打包

打包后的文件为:dist

打包后打开阿帕奇服务器 , 将包放进服务器文件夹下的WWW目录中,服务器地址为localhost 页面地址为 localhost/包名

在打包好的文件中如果页面出不来,将 router (路由) 中的 index.js 的 mode 从 history 改为 hash (去除链接中的 # 用 mode: ' history ' )

如果打包好的页面中无法跳转,检查跳转用的是否为Vue 规定的跳转方法 router-link :to 或者 this.$router.push(" "); 不能用 a 标签跳转

Vue运用实例

购物车功能

<!doctype html>
<html lang="zh-CN">

<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>李硕_购物车</title>

<!-- Bootstrap -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">

<!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
<!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
<!--[if lt IE 9]>
<script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->

<!-- 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<style>
[v-cloak] {
display: none;
}

.table-bordered {
width: 50%;
margin: 0 auto;
}

tr,
td {
text-align: center;
}
</style>
</head>

<body>
 <table class="table table-bordered" id="main">
<thead>
<tr>
<td><input type="checkbox" id="quanxuan" v-on:click='quanxuan_' v-model='quanxuan'>全选</td>
<td>商品名称</td>
<td>商品单价</td>
<td>商品数量</td>
<td>操作</td>
</tr>
</thead>
<tbody>
<tr v-for='(item,index) in sp' >
<td><input type="checkbox" v-on:click='danxuan_(index)' v-bind:checked='item.check'></td>
<td>{{item.name}}</td>
<td>{{item.money}}</td>
<td><input type="button" v-on:click='add(index)' value="+">{{item.num}}<input v-on:click='red(index)' type="button" value="-"></td>
<td><input type="button" value="删除" v-on:click='del(index)'></td>
</tr>
</tbody>
<tfoot>
<tr>
<td>总价:</td>
<td>{{cmoney}}</td>
</tr>
</tfoot>
</table>
<script>
new Vue({
el: '#main',
data() {
return {
quanxuan: false,
zongjia:0,
sp: [
{
id: '1',
name: '苹果',
money: 10,
num: 1,
check: false
},
{
id: '2',
name: '鸭梨',
money: 20,
num: 1,
check: false
}, {
id: '3',
name: '香蕉',
money: 30,
num: 1,
check: false
}
]
}
},
computed: {
// 直接当做普通属性调用不加括号
// 任何data中数据变化立即重新计算
// 计算属性会缓存
cmoney:function(){
let cmoney = 0;
this.sp.forEach(item =>{
if(item.check == true){
cmoney += item.money * item.num;
}
})
return cmoney;
}
// 必须return
},
methods: {
// 数量加
add(index){
this.sp[index].num += 1;
// console.log(this.sp[index].num)
},
// 数量减
red(index){
// console.log(this.sp[index].num)
if(this.sp[index].num > 1){
this.sp[index].num -= 1;
}else{
alert('数量已经为最低!');
}
},
// 删除
del(index){
this.sp.splice(index,1)
},
// 全选
quanxuan_(){
this.quanxuan = ! this.quanxuan
this.sp.forEach(item => {
item.check = this.quanxuan;
});
},
// 单选
danxuan_(index){
this.sp[index].check = !this.sp[index].check;
let a = 0;
this.sp.forEach(item =>{
if(item.check == true){
a++
}
})
if(a == this.sp.length){
this.quanxuan = true;
}else{
this.quanxuan = false;
}
}
},
})
</script>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"
integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ"
crossorigin="anonymous"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"
integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd"
crossorigin="anonymous"></script>
</body>

</html>
npm istall element-ui --save

在 main.js 写入以下内容

import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';

Vue.use(ElementUI);

new Vue({
el: '#app',
render: h => h(App)
});

注意:样式文件需要单独引入。

全局配置: 在引入 Element 时,可以传入一个全局配置对象。该对象目前支持 size zIndex 字段。 size 用于改变组件的默认尺寸, zIndex 设置弹框的初始 z-index(默认值:2000)。按照引入 Element 的方式,具体操作如下:

import Vue from 'vue';
import Element from 'element-ui';
Vue.use(Element, { size: 'small', zIndex: 3000 });

UI 表格中图片遍历问题

 <template>
<el-table :data="tableData" style="width: 100%" :row-class-name="tableRowClassName">
<el-table-column prop="date" label="日期" width="180">
</el-table-column>
<el-table-column prop="title" label="标题" width="180">
</el-table-column>
<el-table-column prop="thumbnail_pic_s" label="图片" width="100">

<!-- 此处为表格中循环数组元素内的图片地址插入 -->
<template slot-scope="scope">
<el-image :src="scope.row.thumbnail_pic_s"></el-image>
</template>
<!-- -->

</el-table-column>

</el-table>
</template>

/deep/

element-ui 改变样式时在css中加 /deep/

img 请求网络地址

有时在 vue 中请求地址为线上地址的 img 时会遇到 img 无法显示的问题

在 src 中这样写 :require ( " 地址 " )

Canvas

canvas会初始化宽度为300像素和高度为150像素。该元素可以使用 CSS 来定义大小,但在绘制时图像会伸缩以适应它的框架尺寸:如果CSS的尺寸与初始画布的比例不一致,它会出现扭曲。

注意: 如果你绘制出来的图像是扭曲的, 尝试用width和height属性为 <canvas> 明确规定宽高,而不是使用CSS。

<canvas id="tutorial" width="150" height="150"></canvas>
const canvas = document.getElementById('canvas');//获取canvas元素
const ctx = canvas.getContext('2d');//获取这个元素的context——图像稍后将在此被渲染,接口完成实际的绘制

ctx.fillStyle = 'green';//fillStyle 属性让长方形变成绿色
ctx.fillRect(10, 10, 150, 100);//fillRect() 方法将它的左上角放在(10, 10),把它的大小设置成宽150高100。

绘制方法:

rect(x, y, width, height) 绘制一个左上角坐标为(x,y),宽高为width以及height的矩形。

.fillRect(x, y, width, height) 绘制一个填充的矩形 .strokeRect(x, y, width, height) 绘制一个矩形的边框 .clearRect(x, y, width, height) 清除指定矩形区域,让清除部分完全透明。 .fillStyle = '' 填充颜色 color 、rgb、rgba、#000

以上的函数绘制之后会马上显现在canvas上,即时生效。不同于路径函数

function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');

ctx.fillRect(25, 25, 100, 100);
ctx.clearRect(45, 45, 60, 60);
ctx.strokeRect(50, 50, 50, 50);
}
}

beginPath() 新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。 closePath() 闭合路径之后图形绘制命令又重新指向到上下文中。 stroke() 通过线条来绘制图形轮廓。 fill() 通过填充路径的内容区域生成实心的图形。

注意: 当前路径为空,即调用 beginPath() 之后,或者canvas刚建的时候,第一条路径构造命令通常被视为是 moveTo() ,无论实际上是什么。出于这个原因,你几乎总是要在设置路径之后专门指定你的起始位置

注意: 当你调用fill()函数时,所有没有闭合的形状都会自动闭合,所以你不需要调用 closePath() 函数。但是调用stroke()时不会自动闭合

绘制一个三角形

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

ctx.beginPath();//新建一条路径
ctx.moveTo(75, 50);//将笔触移动到指定的坐标x以及y上。
ctx.lineTo(100, 75);
ctx.lineTo(100, 25);
ctx.fill();

moveTo(x, y) 将笔触移动到指定的坐标x以及y上。当canvas初始化或者 beginPath() 调用后,你通常会使用 moveTo() 函数设置起点。我们也能够使用 moveTo() 绘制一些不连续的路径。

lineTo(x, y) 绘制一条从当前位置到指定x以及y位置的直线。 x、y ,代表坐标系中直线结束的点。之前路径的结束点就是接下来的开始点、也可以通过 moveTo() 函数改变。

.lineWidth = 设置线宽 .lineCap = type 设置设置线条末端样式。(默认butt round半圆 square方) .lineJoin = type 设定线条与线条间接合处的样式。(默认round圆角 belve不变 miter延申) .miterLimit = value 限制当两条线相交时交接处最大长度;所谓交接处长度(斜接长度)是指线条交接处内角顶点到外角顶点的长度。 .getLineDash() 返回一个包含当前虚线样式,长度为非负偶数的数组。 .setLineDash(segments) 设置当前虚线样式。 lineDashOffset = value 设置虚线样式的起始偏移量。

arc(x, y, radius, startAngle, endAngle, anticlockwise) 画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle(以X轴为基准的弧度)开始到endAngle(以X轴为基准的弧度)结束,按照anticlockwise给定的方向(默认为顺时针 false)来生成。

方向默认为顺时针(false)

弧度 = (Math.PI/180)*角度

注意: arc() 函数中表示角的单位是弧度,不是角度。角度与弧度的js表达式: 弧度=(Math.PI/180) * 角度。

    //绘制了一个圆弧

ctx.beginPath();
// ctx.moveTo(0, 0); // 若与起点连接可以打开这个
let x = (Math.PI/180)*30 //起始为30度
let y = (Math.PI/180)*60 //结束为60度
ctx.arc(0, 0, 50, x, y, false);
// ctx.closePath(); //若闭合则打开这个
ctx.stroke();//以线条绘制轮廓 (不自动闭合)

stroke() 通过线条来绘制图形轮廓。(不自动闭合,需要调用方法闭合) fill() 通过填充路径的内容区域生成实心的图形。(自动闭合)

注意:调用fill()函数时,所有没有闭合的形状都会自动闭合,所以你不需要调用closePath()函数。但是调用stroke()时不会自动闭合

.fillStyle = '' 填充颜色 color 、rgb、rgba、#000 strokeStyle = color 设置图形轮廓的颜色。

注意: 一旦您设置了 strokeStyle 或者 fillStyle 的值,那么这个新值就会成为新绘制的图形的默认值。如果你要给每个图形上不同的颜色,你需要重新设置 fillStyle strokeStyle 的值。

globalAlpha = 0 设置透明度 0-1

就好像一般的绘图软件一样,我们可以用线性或者径向的渐变来填充或描边。我们用下面的方法新建一个 canvasGradient 对象,并且赋给图形的 fillStyle strokeStyle 属性。

createLinearGradient(x1, y1, x2, y2) 方法接受 4 个参数,表示渐变的起点 (x1,y1) 与终点 (x2,y2)。 createRadialGradient(x1, y1, r1, x2, y2, r2) 方法接受 6 个参数,前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。

var lineargradient = ctx.createLinearGradient(0,0,150,150);
var radialgradient = ctx.createRadialGradient(75,75,0,75,75,100);

创建出 canvasGradient 对象后,我们就可以用 addColorStop 方法给它上色了。

.addColorStop(position, color) 方法接受 2 个参数, position 参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置。例如,0.5 表示颜色会出现在正中间。

shadowOffsetX = float X Y 用来设定阴影在 X 和 Y 轴的延伸距离 shadowBlur = float 用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵的影响,默认为 0 shadowColor = color 是标准的 CSS 颜色值,用于设定阴影颜色效果,默认是全透明的黑色。

文字阴影的例子:

  var ctx = document.getElementById('canvas').getContext('2d');

ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.shadowBlur = 2;
ctx.shadowColor = "rgba(0, 0, 0, 0.5)";

ctx.font = "20px Times New Roman";
ctx.fillStyle = "Black";
ctx.fillText("Sample String", 5, 30);

创建文本 fillText(text, x, y [, maxWidth\]) 在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的. strokeText(text, x, y [, maxWidth\]) 在指定的(x,y)位置绘制文本边框,绘制的最大宽度是可选的.

文本样式 font = value 字符串使用和 CSS font 属性相同的语法. 默认的字体是 10px sans-serif textAlign = value 文本对齐选项. 可选的值包括: start , end , left , right or center . 默认值是 start textBaseline = value 基线对齐选项. 可选的值包括: top , hanging , middle , alphabetic , ideographic , bottom 。默认值是 alphabetic。 direction = value 文本方向。可能的值包括: ltr , rtl , inherit 。默认值是 inherit。

ctx.font = "48px serif";
ctx.textBaseline = "hanging";
ctx.strokeText("Hello world", 0, 100);

预测量文本宽度 measureText() 将返回一个 TextMetrics 对象的宽度、所在像素,这些体现文本特性的属性。

var ctx = document.getElementById('canvas').getContext('2d');
var text = ctx.measureText("foo"); // TextMetrics object
text.width; // 16;

Path2D 对象

为了简化代码和提高性能, Path2D 对象已可以在较新版本的浏览器中使用,用来缓存或记录绘画命令,这样你将能快速地回顾路径。

Path2D() 会返回一个新初始化的Path2D对象(可能将某一个路径作为变量——创建一个它的副本,或者将一个包含SVG path数据的字符串作为变量)。

new Path2D();     // 空的Path对象
new Path2D(path); // 克隆Path对象
new Path2D(d); // 从SVG建立Path对象

创建Path2D 对象


var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var rectangle = new Path2D();
rectangle.rect(10, 10, 50, 50);

var circle = new Path2D();
circle.moveTo(125, 35);
circle.arc(100, 35, 25, 0, 2 * Math.PI);

ctx.stroke(rectangle);
ctx.fill(circle);

包管理操作

文件操作: git pull // 将云端的文件从新下载到本地 git clone 项目地址 // 将仓库文件夹克隆到本地 mkdir 文件名 // 创建文件夹 cd 文件名 // 进入文件 cd ../ // 返回上一级 git pull --rebase origin master // 同步云端仓库和自己的仓库

上传操作: git add . // 选择当前文件夹内的所有文件 git commit -m " first commit " // 使文件上传到缓存区,备注(first commit) //上传如果报错 在这一步后加一步同步 git push -u origin master // 上传到git中

当不在master分支的时候 git reset --hard head //回退版本信息

git pull --rebase origin master //合并分支

npm install -g cnpm --registry= https://registry.npm.taobao.org // 下载cnpm

git出现(master|REBASE 1/1)

git rebase --abort  // 取消合并
git rebase --continue // 继续执行

使用npm全局安装yarn

$ npm install -g yarn
//使用npm安装yarn

$ yarn --version
//检查是否安装成功

$ yarn config get registry
//检查安装配置

npm init === yarn init

npm install === yarn 或者 yarn install

npm install taco --save === yarn add taco

npm uninstall taco --save === yarn remove taco

npm install taco --save-dev === yarn add taco --dev

npm update --save === yarn upgrade

npm install taco@latest --save === yarn add taco

npm install taco --global === yarn global add taco

npm init --yes/-y === yarn init --yes/-y

npm link === yarn link

npm outdated === yarn outdated

npm publish === yarn publish

npm run === yarn run

npm cache clean === yarn cache clean

npm login === yarn login

npm test === yarn test
初始化项目:
yarn init // 同npm init,执行输入信息后,会生成package.json文件

yarn的配置项:
yarn config list // 显示所有配置项
yarn config get <key> //显示某配置项
yarn config delete <key> //删除某配置项
yarn config set <key> <value> [-g|--global] //设置配置项

安装包:
yarn install //安装package.json里所有包,并将包及它的所有依赖项保存进yarn.lock
yarn install --flat //安装一个包的单一版本
yarn install --force //强制重新下载所有包
yarn install --production //只安装dependencies里的包
yarn install --no-lockfile //不读取或生成yarn.lock
yarn install --pure-lockfile //不生成yarn.lock

添加包(会更新package.json和yarn.lock):
yarn add [package] // 在当前的项目中添加一个依赖包,会自动更新到package.json和yarn.lock文件中
yarn add [package]@[version] // 安装指定版本,这里指的是主要版本,如果需要精确到小版本,使用-E参数
yarn add [package]@[tag] // 安装某个tag(比如beta,next或者latest)

//不指定依赖类型默认安装到dependencies里,你也可以指定依赖类型:
yarn add --dev/-D // 加到 devDependencies
yarn add --peer/-P // 加到 peerDependencies
yarn add --optional/-O // 加到 optionalDependencies

//默认安装包的主要版本里的最新版本,下面两个命令可以指定版本:
yarn add --exact/-E // 安装包的精确版本。例如yarn add foo@1.2.3会接受1.9.1版,但是yarn add foo@1.2.3 --exact只会接受1.2.3版
yarn add --tilde/-T // 安装包的次要版本里的最新版。例如yarn add foo@1.2.3 --tilde会接受1.2.9,但不接受1.3.0

发布包
yarn publish

移除一个包
yarn remove <packageName>:移除一个包,会自动更新package.json和yarn.lock

更新一个依赖
yarn upgrade 用于更新包到基于规范范围的最新版本

运行脚本
yarn run 用来执行在 package.json 中 scripts 属性下定义的脚本

显示某个包的信息
yarn info <packageName> 可以用来查看某个模块的最新版本信息

缓存
yarn cache
yarn cache list # 列出已缓存的每个包 yarn cache dir # 返回 全局缓存位置 yarn cache clean # 清除缓存

修改git bash 样式 找到安装 git 的文件夹,进去之后,右击 git-bash.exe 选择以管理员身份运行

git clone https://github.com/xnng/my-git-bash.git
cd my-git-bash
git clone https://gitee.com/xnng/bash.git
cd bash

start c://Windows//Fonts && start %cd%/fonts
将字体拉进去

cp .minttyrc ~ && cp git-prompt.sh /etc/profile.d
exit

app.json 为整体的配置文件

pages 为所有页面的地址,(创建新页面也直接在此创建即可)。

"pages": [
"pages/index/index",
"pages/fenlei/fenlei",
"pages/gouwuche/gouwuche",
"pages/me/me"
],

window 为所有页面的配置属性

"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#AB956D",
"backgroundColor": "#eeeeee",
"navigationBarTitleText": "李硕的小程序",
"navigationBarTextStyle": "black"
},

tabBar 为上部(下部)导航栏,list 为导航栏的内容(最少两个最多五个),具体参考文档

"tabBar": {
"list": [//为导航栏页数
{
"pagePath": "pages/index/index",//为导航地址
"text": "营养早餐",//导航名
"iconPath": "./imgs/12.png",//点击前的图片
"selectedIconPath": "./imgs/11.png"//点击后的图片
},
{
"pagePath": "pages/fenlei/fenlei",
"text": "分类",
"iconPath": "./imgs/22.png",
"selectedIconPath": "./imgs/21.png"
}
],
"selectedColor": "#AB956D",//点击前文字的颜色
"backgroundColor": "#fff"//点击后文字的颜色
},

<view> </view> 标签 相当于 div <text> </text> 标签 相当于 span <image> </image> 标签 相当于 img <block> </block> 标签 相当于 template 并不实际渲染在页面上

wxml 就像 vue 采取数据绑定

wx:for 进行列表渲染 使用 wx : key = ' ' 绑定 key 使用 wx : for - item = " " 将遍历后的 item 改变为任意值 使用 wx : for - index = " " 将遍历后的 index 改变为任意值

<view wx:for="{{array}}">
{{item}}
</view>
注意:当wx:for的值为字符串时,会解析为字符串的遍历
wx:for="array"
注意:花括号和引号之间如果有空格,将最终被解析成为字符串
wx:for="{{[1,2,3]}} "

scroll-view

可滑动的 view

wxml部分

<scroll-view scroll-y="true"(y轴可滑动)  scroll-with-animation="true" (滑动动画)scroll-into-view="{{toView}}" (滑动到哪里)>
<view id="bing" class="xqbox">111</view>
<view id="zhou" class="xqbox">222</view>
<view id="mian" class="xqbox">333</view>
</scroll-view>
Page({
data: {
news:[123],
toView:'bing',
boxIndex:0,
category: [
{ name: '烙饼', id: 'bing' },
{ name: '粥类', id: 'zhou' },
{ name: '面点', id: 'mian' }
],
},
bhclick(e){
// console.log(e.currentTarget)
this.setData({
toView:e.currentTarget.id,
boxIndex:e.currentTarget.dataset.index
})
},
})

bindscrolltoupper——滚动到顶部/左边 bindscrolltolower——滚动到底部/右边 bindscroll——滚动的过程

<scroll-view style='height:200px;'scroll-y='true' bindscrolltoupper="upper" bindscrolltolower="lower" bind="scroll">
  upper:function(event){
console.log("滚动到顶部");
},
lower:function(event){
console.log("滚动到底部");
},
scroll:function(event){
console.log("正在滚动");
}

this.data 只能改变数据 不能实时渲染到页面上 使用setData()方法实时改变

Page({
data:{
name:"李硕"
},
change(){
this.setData({
name:"小明"//实时改变
})
this.name = "小明"//只改变数据,页面不变
}
})

tableBar中的页面不能被跳转 只能跳转tableBar中没有的页面

// 保留当前页面,跳转到应用内的某个页面,使用wx.navigateBack可以返回到原页面。
wx.navigateTo({
url: 'page/home/home?user_id=111'
})


// 关闭当前页面,跳转到应用内的某个页面。
wx.redirectTo({
url: 'page/home/home?user_id=111'
})

// 跳转到tabBar页面(在app.json中注册过的tabBar页面),同时关闭其他非tabBar页面。
wx.switchTab({
url: 'page/index/index'
})

// 关闭所有页面,打开到应用内的某个页面。
wx.reLaunch({
url: 'page/home/home?user_id=111'
})

事件绑定: bind绑定; catch绑定;(能阻止事件冒泡)

事件类别: tap:点击事件; longtap:长按事件; touchstart:触摸开始; touchend:触摸结束; touchcansce:取消触摸;

例:绑定点击事件:

<button bindtap="btnclick"></button>

打印一个事件

btnclick:(e){
console.log(e)
}

其中: currentTarget:是我们点击的这个 view; target:是我们目标的这个 view; 可以给这个 view 加一个 id: 在冒泡的事件中: currentTarget 和 target是不一致的; currentTarget是我们绑定了的组件,target是发生事件的组件; currentTarget里面的 dataset是没有数据的。这个是为了方便我们添加我们自定义的属性: 通过点击事件,可以获取到这个空间的属性,从而可以方便我们的逻辑。

自定义属性

使用自定义属性 在单击事件打印事件对象e 就可以拿到自定义的属性值,可以用来传参

      <view class="box {{boxIndex == index?'on':''}}" bindtap="bhclick" id="{{item.id}}" data-name="{{item.name}}" data-index="{{index}}"><text>{{item.name}}</text></view>

切换、添加类名

{{ boxIndex == index ? ' on ' : ' ' }}

boxindex 是否等于 index 若等于 添加类名 on 若不等于 添加类名 ' ' (空)

class="box {{boxIndex == index?'on':''}}"

调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)、微信开放平台帐号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台帐号)及本次登录的会话密钥(session_key)等。用户数据的加解密通讯需要依赖会话密钥完成。更多使用方法详见 小程序登录

wx.login({
success (res) {
if (res.code) {
//发起网络请求
wx.request({
url: 'https://example.com/onLogin',
data: {
code: res.code
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})

wx.login(Object object) | 微信开放文档 (qq.com)

获取 app.js 的数据

onLoad: function (options) {//生命周期函数
const app = getApp()//获取app.js
this.setData({//将app.js的数据赋给本js的数据
goods : app.data.goods
})
},

跳转页面传递参数

方法一 : 利用跳转 url 传值

页面1:跳转传参

tz(e){
wx.navigateTo({//跳转
url:'../xq/xq?name='+goodname,
})
},

液面2:接收参数

onLoad: function (options) {//生命周期函数--监听页面加载
console.log(options)
},

方法二 : 利用 app.js 传值

ios端不支持日期格式中出现 - 使用其他字符代替(/)

区别系统运行的代码

加上 //#ifdef MP-WEIXIN 这个代码的意思是 只在小程序中执行这串代码 H5和APP中的代码,//#endif 这个代码的意思是 就是除了小程序 其他的平台都执行这个代码

uniapp使用微信开发者工具编译

微信开发者工具 设置-》安全—》开启服务端口

vue-3

搭建 viet + vue3 项目

yarn create vite app_name --template vue
//安装yarn + vue3 项目

yarn install
//安装项目依赖

yarn dev
//启动项目

搭建 vue3 项目

$ npm create vite@latest

$ yarn create vite

( vs code vue2 插件:Vuter vue3 插件 Veu Language Features(Volar) )

创建响应式变量、对象

创建响应式变量

import { reactive,ref } from "@vue/runtime-core";//引入ref
let a = ref("");//使用ref创建响应式变量
a.value = 123 //响应式变量赋值
console.log(a.value)//响应式变量取值(注意,在{{}}中不用加value)

let b = reactive({//使用ractive创建响应式对象
lon: "",
lat: "",
height: "",
});

父组件传值/方法

<template>
<DetailsDialogBox class="setbox" :PositionInfo_="PositionInfo_" //PositionInfo_是传递过去的信息
@close="close"/>//close是传递过去的方法
</template>

import DetailsDialogBox from "@/....../.vue";//引入子组件

let PositionInfo_ = reactive({})//传递的对象

var isshow = ref(false);
let close = function () {//传递的方法
isshow.value = false;
};
//获得父组件传递的当地信息
let props = defineProps({ PositionInfo_: Object });//获取值需要在后标注值的类型
//取值console.log(props.PositionInfo_.value)

//获取父组件传递的方法
const close = () => {
emit("close");
};

watch(//监听数据,数据有变化立即执行函数
() => props,//监听props
(props, prevProps) => {
//操作
//props为新数据
//prevProps为旧数据

},
{ deep: true }//深度监听
);

cesium方法总结

添加点,文字(实体)

viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(StationLongitude, StationLatitude, StationHeight),
id: StationNum, //站点编号,供点击事件使用
data: {//需要传递给点击事件的数据
name: StationName, //站点名称,
coordinate: { //站点坐标,
longitude: StationLongitude,
latitude: StationLatitude,
height: StationHeight
},
},
// 点
point: {
color: Cesium.Color.YELLOW, // 点位颜色
pixelSize: 8, // 像素点大小
scale: StationZoom, //缩放
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, //贴地
},
// 文字
label: {
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, //贴地
scale: StationZoom, //缩放
text: StationName, // 文本。支持显式换行符“ \ n”
font: "14pt Source Han Sans CN", // 字体样式,以CSS语法指定字体
fillColor: Cesium.Color.BLUE, // 字体颜色
backgroundColor: "rgba(0,0,0,0)", //Cesium.Color.AQUA
showBackground: false, // 是否显示背景颜色
outline: false, // 字体边框
outlineColor: Cesium.Color.WHITE, // 字体边框颜色
outlineWidth: 10, // 字体边框尺寸
scale: 1.0, //缩放
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
// 相对于坐标的水平位置
verticalOrigin: Cesium.VerticalOrigin.CENTER,
// 相对于坐标的水平位置
horizontalOrigin: Cesium.HorizontalOrigin.BOTTOM,
// 该属性指定标签在屏幕空间中距此标签原点的像素偏移量
pixelOffset: new Cesium.Cartesian2(0, 15),
show: true, //显示
},

});

添加div(信息牌)

let div = document.createElement("div");
div.id = StationNum;
div.setAttribute('class', 'divlabel-container')
div.style.position = "absolute";
div.style.width = "80px";
div.style.height = "30px";
// div.style.backgroundImage = "url(data/imgs/gif_bgi.gif)"
// div.style.backgroundRepeat = "no-repeat"
// div.style.backgroundSize = "cover"
let HTMLTable = `
<div :id="id" class="divlabel-container infobox" v-if="show">
<div class="animate-maker-border">
<p><span class="animate-marker__text">${StationTem}℃</span></p>

</div>
</div>
`;
div.innerHTML = HTMLTable;
viewer.cesiumWidget.container.appendChild(div);
//定位站点信息框
let gisPosition = Cesium.Cartesian3.fromDegrees(
StationLongitude,//div经度
StationLatitude,//div纬度
StationHeight + 800//div高度

);
const canvasHeight = viewer.scene.canvas.height;
const windowPosition = new Cesium.Cartesian2();
Cesium.SceneTransforms.wgs84ToWindowCoordinates(
viewer.scene,
gisPosition,
windowPosition,
);
div.style.bottom = canvasHeight - windowPosition.y + "px";
const elWidth = div.offsetWidth;
div.style.left = windowPosition.x - elWidth / 2 + "px";
//信息框跟随地球移动实时更新位置
viewer.scene.postRender.addEventListener(() => {
const canvasHeight = viewer.scene.canvas.height;
const windowPosition = new Cesium.Cartesian2();
Cesium.SceneTransforms.wgs84ToWindowCoordinates(
viewer.scene,
gisPosition,
windowPosition
);
div.style.bottom = canvasHeight - windowPosition.y + "px";
const elWidth = div.offsetWidth;
div.style.left = windowPosition.x - elWidth / 2 + "px";

}, this);

添加路径线czml格式(高亮材质)

// json路径方法的竖线
// const czml = [
// {
// id: "document",
// name: "StationLine",
// version: "1.0",
// },
// {
// id: StationNum + "_line",
// name:
// "StationLine_",
// polyline: {
// positions: {
// //位置
// cartographicDegrees: [StationLongitude, StationLatitude, StationHeight + 500, StationLongitude, StationLatitude, StationHeight],
// },
// material: {//纹理材质
// polylineGlow: {
// color: {
// rgba: [100, 149, 237, 255],
// },
// glowPower: 0.3,//辉光功率
// // taperPower: 0.5,//锥度
// },
// },
// width: 5,
// },
// },

// ];
// const dataSourcePromise = Cesium.CzmlDataSource.load(czml);
// viewer.dataSources.add(dataSourcePromise);

线实体,图片作为材质

//线 实体 添加图片作为材质
// viewer.entities.add({
// name:
// "Orange line with black outline at height and following the surface",
// polyline: {
// positions: Cesium.Cartesian3.fromDegreesArrayHeights([
// 109.1,
// 34.31,
// 0,
// 109.1,
// 34.31,
// 1000,
// ]),
// width: 50,
// material: new Cesium.ImageMaterialProperty({
// image: 'data/imgs/line2.png',
// repeat: new Cesium.Cartesian2(1.0, 1.0),
// transparent: true,
// color: Cesium.Color.WHITE.withAlpha(1),
// })
// },
// });

流动线实体(着色器实现)

 viewer.entities.add({
polyline: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights([
StationLongitude,
StationLatitude,
StationHeight,
StationLongitude,
StationLatitude,
StationHeight + 800
]),
width: 3,
material: new DynamicFlowMaterialProperty(Cesium.Color.BLUE, 30, 0, 0.8)//颜色,速度,透明度,百分比
},
});

需要引入的Js

export  function DynamicFlowMaterialProperty(color, speed,opacity,percent){
this._definitionChanged = new Cesium.Event();
this.color = color;
this.speed = speed;
this.opacity = opacity;
this.percent = percent;
DynamicFlowMaterialProperty.prototype.init(color, speed,opacity,percent);
}

Object.defineProperties(DynamicFlowMaterialProperty.prototype, {
isConstant: {
get: function () {
return false;
}
},
definitionChanged: {
get: function () {
return this._definitionChanged;
}
}
});

DynamicFlowMaterialProperty.prototype.getType = function (time) {
return 'DynamicFlow';
}
DynamicFlowMaterialProperty.prototype.getValue = function (time, result) {
if (!Cesium.defined(result)) {
result = {};
}
//console.log(" this.color1", this.color);
result.color = this.color;
result.speed = this.speed;
result.opacity = this.opacity;
result.percent =this.percent;
return result;
}
DynamicFlowMaterialProperty.prototype.equals = function (other) {
return false;
//return this === other || (other instanceof DynamicFlowMaterialProperty && Cesium.Property.equals(this._color, other._color));
}
DynamicFlowMaterialProperty.prototype.init = function (color, speed,opacity,percent) {
var sourceStr=`
uniform vec4 color;
uniform float speed;
uniform float percent;
uniform float opacity;
czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
vec2 st = materialInput.st;
float time = fract( czm_frameNumber * speed / 1000.0);
time *= (1.0 + percent);
float alpha = smoothstep(time- percent, time, st.s) * step(-time, -st.s);
alpha += opacity;
material.diffuse= color.rgb;
material.alpha = alpha;
return material;
}
`
// console.log("sourceStr",sourceStr);
// console.log("参数:",color, speed,opacity,percent);
var uniforms={
color: color,
speed: speed,
opacity: opacity,
percent: percent,
};
Cesium.Material._materialCache.addMaterial("DynamicFlow", {
fabric: {
type:"DynamicFlow",
uniforms:uniforms,
source:sourceStr
},
translucent: true
});

}

圆告警扩散


let r1 = 200;
let r2 = 200;
//底座1
viewer.entities.add({
id: StationNum + "_bottom",//更改项
position: Cesium.Cartesian3.fromDegrees(StationLongitude, StationLatitude, StationHeight),//更改项
// billboard: {
// image: 'data/imgs/WARN.png',
// width: 40,
// height: 40,
// horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
// verticalOrigin: Cesium.HorizontalOrigin.Bottom,
// },
ellipse: {
semiMinorAxis: new Cesium.CallbackProperty(function () {
r1 = r1 + 1;
if (r1 >= 200) {
r1 = 0;
}
return r1;
}, false),
semiMajorAxis: new Cesium.CallbackProperty(function () {
r2 = r2 + 1;
if (r2 >= 200) {
r2 = 0;
}
return r2;
}, false),
height: StationHeight,
material: new Cesium.ImageMaterialProperty({
image: 'data/imgs/WARN.png',
repeat: new Cesium.Cartesian2(1.0, 1.0),
transparent: true,
color: Cesium.Color.WHITE.withAlpha(1),
})
}
});

点击地图获取该点经纬度

    var handler= new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (event) {
var earthPosition = viewer.camera.pickEllipsoid(event.position,viewer.scene.globe.ellipsoid);
var cartographic = Cesium.Cartographic.fromCartesian(earthPosition, viewer.scene.globe.ellipsoid, new Cesium.Cartographic());
var lat=Cesium.Math.toDegrees(cartographic.latitude);
var lng=Cesium.Math.toDegrees(cartographic.longitude);
var height=cartographic.height;
console.log("[Lng=>"+lng+",Lat=>"+lat+",H=>"+height+"]");
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);