前端从零开始第六周

368 阅读15分钟

第二十五天

1. 音频——audio

如何嵌入音频

<audio src="audio.mp3" controls preload></audio>

2. 视频——video

如何嵌入视频

<video src="video.mp4" width="320" height="200" controls preload></video>
  • 视频格式:

    • 格式 MIME-type
    • MP4 video/mp4
    • WebM video/webm
    • Ogg video/ogg

3. 音视频的属性、方法及事件

方法

方法说明
addTextTrack()向音/视频添加新的文本轨道
canPlayType()检测浏览器是否能播放
load()重新加载音/视频元素
play()开始播放音/视频
pause()暂停当前播放的音/视频

属性

属性描述
audioTracks返回表示可用音频轨道的 AudioTrackList 对象。
autoplay设置或返回是否在加载完成后随即播放音频/视频。
buffered返回表示音频/视频已缓冲部分的 TimeRanges 对象。
controller返回表示音频/视频当前媒体控制器的 MediaController 对象。
controls设置或返回音频/视频是否显示控件(比如播放/暂停等)。
crossOrigin设置或返回音频/视频的 CORS 设置。
currentSrc返回当前音频/视频的 URL。
currentTime设置或返回音频/视频中的当前播放位置(以秒计)。
defaultMuted设置或返回音频/视频默认是否静音。
defaultPlaybackRate设置或返回音频/视频的默认播放速度。
duration返回当前音频/视频的长度(以秒计)。
ended返回音频/视频的播放是否已结束。
error返回表示音频/视频错误状态的 MediaError 对象。
loop设置或返回音频/视频是否应在结束时重新播放。
mediaGroup设置或返回音频/视频所属的组合(用于连接多个音频/视频元素)。
muted设置或返回音频/视频是否静音。
networkState返回音频/视频的当前网络状态。
paused设置或返回音频/视频是否暂停。
playbackRate设置或返回音频/视频播放的速度。
played返回表示音频/视频已播放部分的 TimeRanges 对象。
preload设置或返回音频/视频是否应该在页面加载后进行加载。
readyState返回音频/视频当前的就绪状态。
seekable返回表示音频/视频可寻址部分的 TimeRanges 对象。
seeking返回用户是否正在音频/视频中进行查找。
src设置或返回音频/视频元素的当前来源。
startDate返回表示当前时间偏移的 Date 对象。
textTracks返回表示可用文本轨道的 TextTrackList 对象。
videoTracks返回表示可用视频轨道的 VideoTrackList 对象。
volume设置或返回音频/视频的音量。

HTML 音频/视频事件

事件描述
abort当音频/视频的加载已放弃时触发。
canplay当浏览器可以开始播放音频/视频时触发。
canplaythrough当浏览器可在不因缓冲而停顿的情况下进行播放时触发。
durationchange当音频/视频的时长已更改时触发。
emptied当目前的播放列表为空时触发。
ended当目前的播放列表已结束时触发。
error当在音频/视频加载期间发生错误时触发。
loadeddata当浏览器已加载音频/视频的当前帧时触发。
loadedmetadata当浏览器已加载音频/视频的元数据时触发。
loadstart当浏览器开始查找音频/视频时触发。
pause当音频/视频已暂停时触发。
play当音频/视频已开始或不再暂停时触发。
playing当音频/视频在因缓冲而暂停或停止后已就绪时触发。
progress当浏览器正在下载音频/视频时触发。
ratechange当音频/视频的播放速度已更改时触发。
seeked当用户已移动/跳跃到音频/视频中的新位置时触发。
seeking当用户开始移动/跳跃到音频/视频中的新位置时触发。
stalled当浏览器尝试获取媒体数据,但数据不可用时触发。
suspend当浏览器刻意不获取媒体数据时触发。
timeupdate当目前的播放位置已更改时触发。
volumechange当音量已更改时触发。
waiting当视频由于需要缓冲下一帧而停止时触发。

第二十六天 ——canvas

作用

画布是H5中一个重要的概念,它面向开发人员提供了非常底层的绘图接口,使得绘制速度可以大幅提高,这对游戏等领域极为重要。

声明

为初始化一个画布,使用canvas标签声明相应的画布元素,使用canvas.getContext('2d')可以获得二维的图形操作上下文,这样就可以开始操纵画布了。

    var canvas = document.querySelector("canvas")
    var content = canvas.getContext('2d')

线条绘制

最简单的莫过于直线,canvas提供了lineTo这样的接口:

context.beginPath();        // 声明创建新的path
context.moveTo(100, 150);
context.lineTo(450, 50);
context.lineWidth = 3;        // 设置直线的宽度,需要先于stroke的调用
context.strokeStyle = '#ff0000';    // 设置线条的颜色 ,需要先于stroke的调用
context.lineCap = 'round';        // 设置圆角样式
context.stroke();    // 真正使得直线可见

弧线

// 幅度制
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);

arc提供的圆的曲线,为了使得曲线能够更加地自由和随意,可以使用 quadraticCurveTo方法。具体来说,首先使用moveTo设置好起点,然后向quadraticCurveTo传入参数(控制点、终止点坐标)

context.moveTo(100, 100);    // 起始点
context.quadraticCurveTo(200, 200, 300, 100);    // 控制点和终止点

形状绘制

利用 直线和弧线,我们能够画出想要的基本图形。

使用lineToarcToquadraticCurveTobezierCurveTo等绘制线条,再使用context.closePath来闭合曲线,形成一个完整的形状。

它也提供了一些基础形状绘制的API,如rect就是用于绘制四边形。为绘制一个圆形,可以使用context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);进行。而半圆的话,就是将里面的参数减半再闭合路径即可。

给形状填充颜色,这通过设置上下文的fillStyle属性即可。举个例子,我们需要对一个矩形填充绿色,可以使用:

context.rect(0, 0, canvas.width, canvas.height);
context.fillStyle = 'green';
context.fill();

当然,我们也可以填充其它更加丰富的内容,如我们可以填充 Linear Gradient 或 Radial Gradient 类型的颜色,这也是通过设置fillStyle达到的:

var grd = context.createLinearGradient(0, 0, canvas.width, canvas.height); 
// var grd = context.createRadialGradient(238, 50, 10, 238, 50, 300);    // 也可以换成 Radial Gradient
​
grd.addColorStop(0, '#8ED6FF');  
grd.addColorStop(1, '#004CB3');
context.fillStyle = grd;    // 设置fillStyle
context.fill();

我们也可以使用图片对形状进行纹理贴图,这一点称为 Pattern,通过调用context.createPattern(imageObj, 'repeat');达到:

var img = new Image();
img.src = "./img.jpg";
img.onload = function () {
    var pattern = context.createPattern(img, 'repeat');    // 后一个参数各类:repeat, repeat-x, repeat-y, no-repeat
    context.fillStyle = pattern;
    context.fill();
}

图像文本操作

drawImage这个方法可以给我们提供在画布上直接绘制图像的能力,一般情况下,我们需要等到图像完全加载完以后才能调用drawImage,drawImage的接口包含图像、绘制坐标、图像大小(可选):

var img = new Image();
img.src = "./img.png";
img.onload = function () {
     context.drawImage(img, 10, 10, 200, 200);    // 在画布坐标(10,10)处开始绘制大小为200 * 200的图像  
}

但有时候,我们可能只需要截取图像中的一部分内容绘制到画布上,drawImage也是支持这种样式的。其调用接口为:

// 其中(srcX, srcY)表示图像的左上角开始的坐标进行裁剪,大小为srcWidth * srcHeight,并绘制到画布(dstX, dstY)坐标上
context.drawImage(img, srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight);

canvas还具有绘制文本的能力,fillText方法可以向画布上绘制文字,而context.font用于设置文本的字体。 前面提到 fillStyle用于 填充形状颜色,它也可以用于设置文本的颜色。

context.font = 'italic 40pt Arial';
context.fillStyle = 'red';
context.fillText('Hello World!', 150, 100);

如果我们希望显示文本的边界,这时strokeText就非常地实用。

context.font = '60pt Calibri';
context.lineWidth = 3;
context.strokeStyle = 'blue'; 
context.strokeText("ABCDEFG", 100, 100);

如果希望文本既显示实体内容,也显示边界,那么fillText和strokeText都需要调用。

context.font = '60pt Calibri';
context.lineWidth = 3;
// stroke color
context.fillText("Hello World!", x, y);
context.strokeStyle = 'blue';
context.strokeText('Hello World!', x, y);
//设置文本的垂直对齐方式。
context.textBaseline = // start ,  end ,  left , center , or  right .

几何变换

拥有几何变换,我们能让图像作出我们想要的任何行为

几何变换一般包括:旋转(rotate)、平移(translate)、缩放(scale),为支持任意的变换,canvas也提供了transform这个方法 。本质上,它会先对context进行几何变换,然后再绘制。

context.translate(x, y)
context.scale(1, 1.2);
context.rotate(Math.PI / 4);    // 以原点开始逆时针旋转
context.transform(a, b, c, d, e, f);
// 参数对应于如下矩阵
// a c e
// b d f
// 0 0 1

但有时候,我们可能希望对不同几何体应用不同变换,这时就需要重置之前的变换矩阵,通过向setTransform这个方法传入一个单位矩阵即可实现这个目的。但是,从另一个角度上来说,每次这样重置是很繁琐的,所以canvas还提供了一个save和restore方法对变换状态进行管理。

案例

[​canvas实现时钟和画板] gitee.com/szCodeMan/d…

第二十七天 ——SVG

SVG(可伸缩矢量图形的简写)

SVG 是一种矢量图像文件格式。这使得它们与 PNG、GIF 或 JPG 等图像格式非常不同,后者是光栅图像文件格式。

SVG 成功的部分原因是我们必须支持各种不同分辨率和尺寸的屏幕显示。SVG 的完美任务。

1. SVG的优点

可以无限缩放并且不会出现图像质量下降的任何问题。

因为 SVG 图像是使用XML 标记构建的,浏览器通过绘制每个点和线来打印它们,而不是用预定义的像素填充一些空间。

由于在 XML 中定义,SVG 图像比 JPG 或 PNG 图像灵活得多,并且我们可以使用 CSS 和 JavaScript 与它们进行交互。SVG 图像甚至可以包含CSS 和 JavaScript。

2. 页面使用SVG

SVG 文件可以直接插入网页,成为 DOM 的一部分,然后用 JavaScript 和 CSS 进行操作。

<!DOCTYPE html>
<html>
<head></head>
<body>
<svg
  id="mysvg"
  xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 800 600"
  preserveAspectRatio="xMidYMid meet"
>
  <circle id="mycircle" cx="400" cy="300" r="50" />
</svg>
</body>
</html>

SVG 代码也可以写在一个独立文件中,然后用<img><object><embed><iframe>等标签插入网页。

<img src="circle.svg">
<object id="object" data="circle.svg" type="image/svg+xml"></object>
<embed id="embed" src="icon.svg" type="image/svg+xml">
<iframe id="iframe" src="icon.svg"></iframe>

CSS 也可以使用 SVG 文件。

.logo {
  background: url(icon.svg);
}

SVG 文件还可以转为 BASE64 编码,然后作为 Data URI 写入网页。

<img src="data:image/svg+xml;base64,[data]">

3. 语法

3.1 <svg>标签

SVG 代码都放在顶层标签<svg>之中。下面是一个例子。

<svg width="100%" height="100%">
  <circle id="mycircle" cx="50" cy="50" r="50" />
</svg>

的width属性和height属性,指定了 SVG 图像在 HTML 元素中所占据的宽度和高度。除了相对单位,也可以采用绝对单位(单位:像素)。如果不指定这两个属性,SVG 图像默认大小是300像素(宽) x 150像素(高)。

如果只想展示 SVG 图像的一部分,就要指定viewBox属性。

<svg width="100" height="100" viewBox="50 50 50 50">
  <circle id="mycircle" cx="50" cy="50" r="50" />
</svg>

<viewBox>属性的值有四个数字,分别是左上角的横坐标和纵坐标、视口的宽度和高度。上面代码中,SVG 图像是100像素宽 x 100像素高,viewBox属性指定视口从(50, 50)这个点开始。所以,实际看到的是右下角的四分之一圆。

注意,视口必须适配所在的空间。上面代码中,视口的大小是 50 x 50,由于 SVG 图像的大小是 100 x 100,所以视口会放大去适配 SVG 图像的大小,即放大了四倍。

如果不指定width属性和height属性,只指定viewBox属性,则相当于只给定 SVG 图像的长宽比。这时,SVG 图像的默认大小将等于所在的 HTML 元素的大小。

3.2 <circle>标签

<circle>标签代表圆形。

<svg width="300" height="180">
  <circle cx="30"  cy="50" r="25" />
  <circle cx="90"  cy="50" r="25" class="red" />
  <circle cx="150" cy="50" r="25" class="fancy" />
</svg>

上面的代码定义了三个圆。<circle>标签的cxcyr属性分别为横坐标、纵坐标和半径,单位为像素。坐标都是相对于<svg>画布的左上角原点。

class属性用来指定对应的 CSS 类。

.red {
  fill: red;
}
​
.fancy {
  fill: none;
  stroke: black;
  stroke-width: 3pt;
}

SVG 的 CSS 属性与网页元素有所不同。

  • fill:填充色
  • stroke:描边色
  • stroke-width:边框宽度

3.3 <line>标签

<line>标签用来绘制直线。

<svg width="300" height="180">
  <line x1="0" y1="0" x2="200" y2="0" style="stroke:rgb(0,0,0);stroke-width:5" />
</svg>

上面代码中,<line>标签的x1属性和y1属性,表示线段起点的横坐标和纵坐标;x2属性和y2属性,表示线段终点的横坐标和纵坐标;style属性表示线段的样式。

3.4 <polyline>标签

<polyline>标签用于绘制一根折线。

<svg>
  <polyline 
            points="20,20 40,25 60,40 80,120 120,140 200,180"
            stroke="purple"
            stroke-width="1"
            fill="none"
            ></polyline>
</svg>
        

<polyline>points属性指定了每个端点的坐标,横坐标与纵坐标之间与逗号分隔,点与点之间用空格分隔。

3.5 <rect>标签

<rect>标签用于绘制矩形。

<svg width="150" height="200" viewbox="150,0,150,200">
            <!-- <rect x="50" y="20" width="150" height="70"
                stroke="black"
                stroke-width="4"
                fill='yellow'
            ></rect> -->
            
            <rect  
                rx="20" ry="20"
                x="50" y="20" width="150" height="70"
                fill-opacity="0.1"
                style="stroke: green;fill: yellow;y:50;stroke-width: 5; stroke-opacity: 0.1;"
            ></rect>
            <rect
                rx="20" ry="20"
                x="200" y="20" width="150" height="70"
                fill-opacity="0.1"
                style="stroke: green;fill: red;y:50;stroke-width: 5; stroke-opacity: 0.1;"
            ></rect>
        </svg>

<rect>x属性和y属性,指定了矩形左上角端点的横坐标和纵坐标;width属性和height属性指定了矩形的宽度和高度(单位像素)。

3.6 <ellipse>标签

<ellipse>标签用于绘制椭圆。

<svg width='400' height="300">
  <ellipse 
           cx="200" cy="150" rx="100" ry="50"
           class="el"
           ></ellipse>
  <rect
        rx="20" ry="20"
        x="50" y="20" width="150" height="70"
        fill-opacity="0.1"
        style="stroke: green;fill: yellow;y:50;stroke-width: 5; stroke-opacity: 0.1;"
        ></rect>
</svg>

<ellipse>cx属性和cy属性,指定了椭圆中心的横坐标和纵坐标(单位像素);rx属性和ry属性,指定了椭圆横向轴和纵向轴的半径(单位像素)。

3.7 <polygon>标签

<polygon>标签用于绘制多边形。

<svg width="800" height="600">
            <!-- 通过多点形成多边形 -->
            <!-- <polygon
                points="200,10 250,190 160,210"
                stroke="purple"
                stroke-width="10"
                fill="green"
            ></polygon> -->
            
  <polygon
           points="100,10 40,198 190,78 10,78 160,198"
           stroke="purple"
           stroke-width="1"
           fill="green"
           fill-rule="evenodd"
           ></polygon>
​
​
</svg>

<polygon>points属性指定了每个端点的坐标,横坐标与纵坐标之间与逗号分隔,点与点之间用空格分隔。

3.8 <path>标签

<path>标签用于制路径。

<svg width="300" height="180">
<path d="
  M 18,3
  L 46,3
  L 46,40
  L 61,40
  L 32,68
  L 3,40
  L 18,40
  Z
"></path>
</svg>

<path>d属性表示绘制顺序,它的值是一个长字符串,每个字母表示一个绘制动作,后面跟着坐标。

  • M:移动到(moveto)
  • L:画直线到(lineto)
  • Z:闭合路径

3.9 <text>标签

<text>标签用于绘制文本。

<svg width="300" height="180">
  <text x="50" y="25">Hello World</text>
</svg>

<text>x属性和y属性,表示文本区块基线(baseline)起点的横坐标和纵坐标。文字的样式可以用classstyle属性指定。

3.10 <use>标签

<use>标签用于复制一个形状。

<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
  <circle id="myCircle" cx="5" cy="5" r="4"/>
​
  <use href="#myCircle" x="10" y="0" fill="blue" />
  <use href="#myCircle" x="20" y="0" fill="white" stroke="blue" />
</svg>

<use>href属性指定所要复制的节点,x属性和y属性是<use>左上角的坐标。另外,还可以指定widthheight坐标。

3.11 <g>标签

<g>标签用于将多个形状组成一个组(group),方便复用。

<svg width="300" height="100">
  <g id="myCircle">
    <text x="25" y="20">圆形</text>
    <circle cx="50" cy="50" r="20"/>
  </g>
​
  <use href="#myCircle" x="100" y="0" fill="blue" />
  <use href="#myCircle" x="200" y="0" fill="white" stroke="blue" />
</svg>

3.12 <defs>标签

<defs>标签用于自定义形状,它内部的代码不会显示,仅供引用。

<svg width="300" height="100">
  <defs>
    <g id="myCircle">
      <text x="25" y="20">圆形</text>
      <circle cx="50" cy="50" r="20"/>
    </g>
  </defs>
​
  <use href="#myCircle" x="0" y="0" />
  <use href="#myCircle" x="100" y="0" fill="blue" />
  <use href="#myCircle" x="200" y="0" fill="white" stroke="blue" />
</svg>

3.13 <pattern>标签

<pattern>标签用于自定义一个形状,该形状可以被引用来平铺一个区域。

<svg width="500" height="500">
  <defs>
    <pattern id="dots" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
      <circle fill="#bee9e8" cx="50" cy="50" r="35" />
    </pattern>
  </defs>
  <rect x="0" y="0" width="100%" height="100%" fill="url(#dots)" />
</svg>

上面代码中,<pattern>标签将一个圆形定义为dots模式。patternUnits="userSpaceOnUse"表示<pattern>的宽度和长度是实际的像素值。然后,指定这个模式去填充下面的矩形。

3.14 <image>标签

<image>标签用于插入图片文件。

<svg viewBox="0 0 100 100" width="100" height="100">
  <image xlink:href="path/to/image.jpg"
    width="50%" height="50%"/>
</svg>

上面代码中,<image>xlink:href属性表示图像的来源。

3.15 <animate>标签

<animate>标签用于产生动画效果。

<svg width="500px" height="500px">
  <rect x="0" y="0" width="100" height="100" fill="#feac5e">
    <animate attributeName="x" from="0" to="500" dur="2s" repeatCount="indefinite" />
  </rect>
</svg>

上面代码中,矩形会不断移动,产生动画效果。

<animate>的属性含义如下。

  • attributeName:发生动画效果的属性名。
  • from:单次动画的初始值。
  • to:单次动画的结束值。
  • dur:单次动画的持续时间。
  • repeatCount:动画的循环模式。

可以在多个属性上面定义动画。

<animate attributeName="x" from="0" to="500" dur="2s" repeatCount="indefinite" />
<animate attributeName="width" to="500" dur="2s" repeatCount="indefinite" />

3.16 <animateTransform>标签

<animate>标签对 CSS 的transform属性不起作用,如果需要变形,就要使用<animateTransform>标签。

<svg width="500px" height="500px">
  <rect x="250" y="250" width="50" height="50" fill="#4bc0c8">
    <animateTransform attributeName="transform" type="rotate" begin="0s" dur="10s" from="0 200 200" to="360 400 400" repeatCount="indefinite" />
  </rect>
</svg>

上面代码中,<animateTransform>的效果为旋转(rotate),这时fromto属性值有三个数字,第一个数字是角度值,第二个值和第三个值是旋转中心的坐标。from="0 200 200"表示开始时,角度为0,围绕(200, 200)开始旋转;to="360 400 400"表示结束时,角度为360,围绕(400, 400)旋转。

4. 对Svg进行操作

4.1 DOM 操作

如果 SVG 代码直接写在 HTML 网页之中,它就成为网页 DOM 的一部分,可以直接用 DOM 操作。

<svg
  id="mysvg"
  xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 800 600"
  preserveAspectRatio="xMidYMid meet"
>
  <circle id="mycircle" cx="400" cy="300" r="50" />
<svg>

上面代码插入网页之后,就可以用 CSS 定制样式。

circle {
  stroke-width: 5;
  stroke: #f00;
  fill: #ff0;
}
​
circle:hover {
  stroke: #090;
  fill: #fff;
}

然后,可以用 JavaScript 代码操作 SVG。

var mycircle = document.getElementById('mycircle');
​
mycircle.addEventListener('click', function(e) {
  console.log('circle clicked - enlarging');
  mycircle.setAttribute('r', 60);
}, false);

上面代码指定,如果点击图形,就改写circle元素的r属性。

4.2 获取 SVG DOM

使用<object><iframe><embed>标签插入 SVG 文件,可以获取 SVG DOM。

var svgObject = document.getElementById('object').contentDocument;
var svgIframe = document.getElementById('iframe').contentDocument;
var svgEmbed = document.getElementById('embed').getSVGDocument();

注意,如果使用<img>标签插入 SVG 文件,就无法获取 SVG DOM。

4.3 读取 SVG 源码

由于 SVG 文件就是一段 XML 文本,因此可以通过读取 XML 代码的方式,读取 SVG 源码。

<div id="svg-container">
  <svg
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xml:space="preserve" width="500" height="440"
  >
    <!-- svg code -->
  </svg>
</div>

使用XMLSerializer实例的serializeToString()方法,获取 SVG 元素的代码。

var svgString = new XMLSerializer()
  .serializeToString(document.querySelector('svg'));

4.4 SVG 图像转为 Canvas 图像

首先,需要新建一个Image对象,将 SVG 图像指定到该Image对象的src属性。

var img = new Image();
var svg = new Blob([svgString], {type: "image/svg+xml;charset=utf-8"});
​
var DOMURL = self.URL || self.webkitURL || self;
var url = DOMURL.createObjectURL(svg);img.src = url;

然后,当图像加载完成后,再将它绘制到<canvas>元素。

img.onload = function () {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0);
};

案例

[描边动画] gitee.com/szCodeMan/d…

第二十八天

1. WebWoker

1.1 简介

Javascript单线程执行的基础上,开启一个子线程,进行程序处理,而不影响主线程的执行,当子线程执行完毕之后再回到主线程上,在这个过程中并不影响主线程的执行过程。

1.2 基本使用

创建新的Worker
var worker = new Worker("worker.js")
传递参数
worker.postMessage("text");
接收信息
worker.onmessage = function (e) {
        var message = e.data;
};
异常处理
worker.onerror = function(e){
    console.log("error at "+e.filename ":" + e.lineno + e.message)
}
结束worker
worker.terminate();
载入工具类函数
importScripts("./utils/base64.js","./utils/map.js"...)

需要注意的是importScripts是同步方法,一旦importScripts方法返回就可以开始使用载入的脚本,而不需要回调函数。

1.3 示例:异步计算

<h1>请输入需要从1相加到n的值,计算结果是:<span class="sum">0</span></h1>
<input type="text" name="" id="input" value="" />
<button id="sumClick">计算结果</button><h1>按钮的点击数:<span class="num">0</span></h1>
<button id="clickBtn">计算点击按钮的次数</button>
<script type="text/javascript">
  // 创建webworker
  var worker = new Worker("worker.js")
  // 事件监听
  worker.onmessage = function(event){
    console.log(event)
    console.log(event.data)
    // 将woker计算的结果返回给到主线程,并且显示到页面上
    sumSpan.innerHTML = event.data.result
  }
​
  //给worker发送数据
  worker.postMessage("给子线程发送数据")
​
​
​
  // 将n值相加
  var sumClick = document.querySelector('#sumClick')
  var sumSpan = document.querySelector('.sum')
  var input = document.querySelector('#input')
  sumClick.onclick = function(){
    var n = parseInt(input.value);
    // 告诉worker要计算到什么值
    worker.postMessage(n)
​
​
​
  }
  // 点击次数就可以将次数显示在页面上
  var clickBtn = document.querySelector('#clickBtn');
  var num = 0;
  var span = document.querySelector('span.num')
  clickBtn.onclick = function(){
    num++
    span.innerHTML = num
  }
​
</script>
// 将计算的结果发送给主线程
// postMessage(sum)
​
onmessage = function(event){
  var n = event.data;
  // 1+2+3+4......+10000
  var index = 1;
  var sum = 0
  // document.querySelector('div')
  while(index<=n){
    sum+=index;
    index++
  }
  postMessage({event:"计算事件",result:sum})
}

1.4 Worker作用域

当我们创建一个新的worker时,改代码会运行在一个全新的javascript的环境中(WorkerGlobalScope)运行,是完全和创建worker的脚本隔离,这时我们可以吧创建新worker的脚本叫做主线程,而被创建的新的worker叫做子线程。

WorkerGlobalScope是worker的全局对象,所以它包含所有核心javascript全局对象拥有的属性如JSON等,window的一些属性,也拥有类似于XMLHttpRequest()等。

但是我们所开启的新的worker也就是子线程,并不支持操作页面的DOM。

2. 正则应用

2.1 正则表达式创建

JavaScript 有两种方式创建正则表达式:

  • 第一种:直接通过/正则表达式/写出来 (字面量形式)
  • 第二种:通过new RegExp('正则表达式')创建一个RegExp对象 (对象形式)
const re1 = /ABC-001/;
const re2 = new RegExp('ABC\-001');
​
re1; // /ABC-001/
re2; // /ABC-001/

注意,如果使用第二种写法,因为字符串的转义问题,字符串的两个\实际上是一个\。

2.2 规则

字符含义
\匹配将依照下列规则: 在非特殊字符之前的反斜杠表示下一个字符是特殊的,不能从字面上解释。例如,前面没有''的'd'通常匹配小写'd'。如果加了'',这个字符变成了一个特殊意义的字符,意思是匹配一个数字。 反斜杠也可以将其后的特殊字符,转义为字面量。例如,模式 /a / 代表会匹配 0 个或者多个 a。相反,模式 /a/ 将 '* ' 的特殊性移除,从而可以匹配像 "a*" 这样的字符串。 使用 new RegExp("pattern") 的时候也不要忘记将 \ 进行转义,因为 \ 在字符串里面也是一个转义字符。
匹配输入的开始,例如,/^A/ 并不会匹配 "an A" 中的 'A',但是会匹配 "An E" 中的 'A'。
$匹配输入的结束。例如,/t$/ 并不会匹配 "eater" 中的 't',但是会匹配 "eat" 中的 't'。
*匹配前一个表达式0次或多次。等价于 {0,}。例如,/bo*/会匹配 "A ghost boooooed" 中的 'booooo'
+匹配前面一个表达式1次或者多次。等价于 {1,}。例如,/a+/匹配了在 "candy" 中的 'a',和在 "caaaaaaandy" 中所有的 'a'。
?匹配前面一个表达式0次或者1次。等价于 {0,1}。例如,/e?le?/ 匹配 "angel" 中的 'el',和 "angle" 中的 'le' 以及"oslo' 中的'l'。 如果紧跟在任何量词 *、 +、? 或 {} 的后面,将会使量词变为非贪婪的(匹配尽量少的字符),和缺省使用的贪婪模式(匹配尽可能多的字符)正好相反。 例如,对 "123abc" 应用 /\d+/ 将会返回 "123",如果使用 /\d+?/,那么就只会匹配到 "1"。
.匹配除换行符之外的任何单个字符。例如,/.n/将会匹配 "nay, an apple is on the tree" 中的 'an' 和 'on',但是不会匹配 'nay'。
{n}n是一个正整数,匹配了前面一个字符刚好发生了n次。 比如,/a{2}/不会匹配“candy”中的'a',但是会匹配“caandy”中所有的a,以及“caaandy”中的前两个'a'。
{n,m}n 和 m 都是整数。匹配前面的字符至少n次,最多m次。如果 n 或者 m 的值是0, 这个值被忽略。例如,/a{1, 3}/ 并不匹配“cndy”中的任意字符,匹配“candy”中的a,匹配“caandy”中的前两个a,也匹配“caaaaaaandy”中的前三个a。注意,当匹配”caaaaaaandy“时,匹配的值是“aaa”,即使原始的字符串中有更多的a。
[xyz]一个字符集合。匹配方括号中的任意字符,包括转义序列。你可以使用破折号(-)来指定一个字符范围。对于点(.)和星号(*)这样的特殊符号在一个字符集中没有特殊的意义。他们不必进行转义,不过转义也是起作用的。 例如,[abcd] 和[a-d]是一样的。他们都匹配"brisket"中的‘b’,也都匹配“city”中的‘c’。/[a-z.]+/ 和/[\w.]+/与字符串“test.i.ng”匹配。
[^xyz]一个反向字符集。也就是说, 它匹配任何没有包含在方括号中的字符。你可以使用破折号(-)来指定一个字符范围。任何普通字符在这里都是起作用的。
\b匹配一个词的边界。一个词的边界就是一个词不被另外一个“字”字符跟随的位置或者没有其他“字”字符在其前面的位置。注意,一个匹配的词的边界并不包含在匹配的内容中。换句话说,一个匹配的词的边界的内容的长度是0。例如: /\bm/匹配“moon”中的‘m’;/oo\b/并不匹配"moon"中的'oo',因为'oo'被一个“字”字符'n'紧跟着。/oon\b/匹配"moon"中的'oon',因为'oon'是这个字符串的结束部分。这样他没有被一个“字”字符紧跟着。
\d匹配一个数字。等价于[0-9]。例如, /\d/ 或者 /[0-9]/ 匹配"B2 is the suite number."中的'2'。
\D匹配一个非数字字符。等价于0-9。例如, /\D/ 或者 /0-9/ 匹配"B2 is the suite number."中的'B' 。
\f匹配一个换页符 (U+000C)。
\n匹配一个换行符 (U+000A)。
\r匹配一个回车符 (U+000D)。
\s匹配一个空白字符,包括空格、制表符、换页符和换行符。等价于[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。 例如, /\s\w*/ 匹配"foo bar."中的' bar'。
\S匹配一个非空白字符。等价于 \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff。 例如, /\S\w*/ 匹配"foo bar."中的'foo'。
\t匹配一个水平制表符 (U+0009)。
\w匹配一个单字字符(字母、数字或者下划线)。等价于[A-Za-z0-9_]。 例如, /\w/ 匹配 "apple," 中的 'a',"$5.28,"中的 '5' 和 "3D." 中的 '3'。
\W匹配一个非单字字符。
\n在正则表达式中,它返回最后的第n个子捕获匹配的子字符串(捕获的数目以左括号计数)。

2.3 应用

2.3.1 分割字符串 split

用正则表达式切分字符串比用固定的字符更灵活,

// 通常的切分代码:
'a d   c'.split(' '); // ['a', 'd', '', '', 'c']
// 正则
'a,b;; c  d'.split(/[\s,;]+/); // ['a', 'b', 'c', 'd']
2.3.2 分组

^(\d{4})-(\d{4,9})$分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码:用()表示的就是要提取的分组(Group)

var re = /^(\d{4})-(\d{4,9})$/;
re.exec('0530-12306'); // ['010-12345', '010', '12345']
re.exec('0530 12306'); // null
​
var re = /^(\d{4})-(\d{4,9})$/;
re.test('0530-12321'); // true
re.test('0530-123ab'); // false
re.test('0530 12321'); // false

exec()方法在匹配成功后,返回一个数组,第一个元素是正则表达式匹配到的整个字符串,后面的字符串表示匹配成功的子串。

exec()方法在匹配失败时返回null。

test() 方法用于检测一个字符串是否匹配某个模式,如果字符串中含有匹配的文本,则返回 true,否则返回 false。

2.3.3 正则表达式标志
g 全局搜索。
i 不区分大小写搜索。
m 多行搜索。
y 执行“粘性”搜索,匹配从目标字符串的当前位置开始,可以使用y标志。

3. 案例参考

验证Email地址:^\w+[-+.]\w+)*@\w+([-.]\w+)*.\w+([-.]\w+)*$
验证身份证号(15位或18位数字):^\d{15}|\d{}18$
​
中国大陆手机号码:1\d{10}
中国大陆固定电话号码:(\d{4}-|\d{3}-)?(\d{8}|\d{7})
中国大陆邮政编码:[1-9]\d{5}
​
IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?).){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
​
日期(年-月-日):(\d{4}|\d{2})-((1[0-2])|(0?[1-9]))-(([12][0-9])|(3[01])|(0?[1-9]))
日期(月/日/年):((1[0-2])|(0?[1-9]))/(([12][0-9])|(3[01])|(0?[1-9]))/(\d{4}|\d{2})
​
​
验证数字:^[0-9]*$
验证n位的数字:^\d{n}$
验证至少n位数字:^\d{n,}$
验证m-n位的数字:^\d{m,n}$
验证零和非零开头的数字:^(0|[1-9][0-9]*)$
验证有1-3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
验证非零的正整数:^+?[1-9][0-9]*$
验证非零的负整数:^-[1-9][0-9]*$
验证非负整数(正整数 + 0) ^\d+$
验证非正整数(负整数 + 0) ^((-\d+)|(0+))$
验证长度为3的字符:^.{3}$
验证由26个英文字母组成的字符串:^[A-Za-z]+$
验证由26个大写英文字母组成的字符串:^[A-Z]+$
验证由26个小写英文字母组成的字符串:^[a-z]+$
验证由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$

第二十九天 —— 轮播图案例

详细 gitee.com/szCodeMan/d…

<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>
    <style>
      .wrapper {
        width: 800px;
        height: 600px;
        margin: 100px auto;
        overflow: hidden;
        position: relative;
      }

      .imgList {
        width: 100%;
        height: 100%;
        position: relative;
      }
      .imgItem {
        width: 100%;
        height: 100%;
        position: absolute;
        left: 0;
        top: 0;
      }

      .imgItem img {
        width: 800px;
        height: 600px;
        /* border-radius: 30px; */
      }

      .activeRight {
        animation: isActiveRight 0.8s ease forwards;
      }
      @keyframes isActiveRight {
        from {
          z-index: 10;
          transform: translateX(-100%);
        }
        to {
          z-index: 10;
          transform: translateX(0);
        }
      }

      .unActiveRight {
        animation: unActiveRight 0.8s ease forwards;
      }
      @keyframes unActiveRight {
        from {
          z-index: 10;
          transform: translateX(0);
        }
        to {
          z-index: 10;
          transform: translateX(100%);
        }
      }

      .activeLeft {
        animation: activeLeft 0.8s ease forwards;
      }
      @keyframes activeLeft {
        from {
          z-index: 10;
          transform: translateX(100%);
        }
        to {
          z-index: 10;
          transform: translateX(0);
        }
      }

      .unActiveLeft {
        animation: unActiveLeft 0.8s ease forwards;
      }
      @keyframes unActiveLeft {
        from {
          z-index: 10;
          transform: translateX(0);
        }
        to {
          z-index: 10;
          transform: translateX(-100%);
        }
      }

      .btnBox {
        z-index: 11;
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        width: 50px;
        height: 50px;
        border-radius: 50%;
        background-color: rgba(0, 0, 0, 0.6);
        display: flex;
        justify-content: center;
        align-items: center;
        cursor: pointer;
      }
      .rightBtn {
        right: 10px;
      }
      .leftBtn {
        left: 10px;
      }

      .point-wrapper {
        z-index: 11;
        position: absolute;
        bottom: 20px;
        left: 50%;
        width: 200px;
        transform: translateX(-50%);
        display: flex;
        flex-direction: row;
        justify-content: space-around;
        align-items: center;
      }

      .point {
        width: 20px;
        height: 20px;
        border-radius: 50%;
        background-color: #fff;
        transition: all 0.4s ease-in;
      }

      .activePoint {
        box-shadow: 0px 0px 5px 5px rgb(252, 73, 73);
      }

      #box {
        position: relative;
        margin: 100px auto;
        overflow: hidden;
        position: relative;
      }
    </style>
  </head>
  <body>
    <div class="wrapper">
      <div class="imgList">
        <div class="imgItem activeRight"><img src="./img/1.jpg" /></div>
        <div class="imgItem"><img src="./img/2.jpg" /></div>
        <div class="imgItem"><img src="./img/3.jpg" /></div>
        <div class="imgItem"><img src="./img/4.jpg" /></div>
        <div class="imgItem"><img src="./img/5.jpg" /></div>
        <div class="imgItem"><img src="./img/6.jpg" /></div>
      </div>
      <div class="btnBox rightBtn">
        <img src="./icon/向右箭头.svg" width="30" height="30" alt="" />
      </div>
      <div class="btnBox leftBtn">
        <img src="./icon/向左箭头.svg" width="30" height="30" alt="" />
      </div>

      <div class="point-wrapper"></div>
    </div>

    <script>
      var imgList = document.querySelectorAll(".wrapper .imgList .imgItem");
      var pointWrapper = document.querySelector(".wrapper .point-wrapper");
      imgList.forEach((item, i) => {
        if (i == 0)
          pointWrapper.innerHTML += `<div class="point activePoint"></div>`;
        else pointWrapper.innerHTML += `<div class="point"></div>`;
      });
      var currentNum = 0;
      var beforeNum = null;
      var pointList = document.querySelectorAll(
        ".wrapper .point-wrapper .point"
      );

      var rightBtn = document.querySelector(".rightBtn");
      rightBtn.addEventListener("click", rightImg);
      function rightImg() {
        beforeNum = currentNum;
        currentNum++;
        if (currentNum === imgList.length) currentNum = 0;
        imgList[currentNum].className = "imgItem activeRight";
        imgList[beforeNum].className = "imgItem unActiveRight";
        setPointActive();
      }

      var leftBtn = document.querySelector(".leftBtn");
      leftBtn.addEventListener("click", function () {
        beforeNum = currentNum;
        currentNum--;
        if (currentNum < 0) currentNum = imgList.length - 1;
        imgList[currentNum].className = "imgItem activeLeft";
        imgList[beforeNum].className = "imgItem unActiveLeft";
        setPointActive();
      });

      function setPointActive() {
        pointList[currentNum].className = "point activePoint";
        pointList[beforeNum].className = "point";
        clearInterval(timer);
        timer = setInterval(rightImg, 3000);
      }
      var timer = setInterval(rightImg, 3000);
    </script>
  </body>
</html>
`