整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

JavaScript入门简介

JavaScript入门简介

么是 JavaScript

JavaScript,我们一般简称为 JS,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。

JavaScript 现在已经被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并支持面向对象、命令式和声明式风格。

HTML、CSS、JavaScript三者不同的功能:

  • HTML:定义网页的内容。
  • CSS:描述页面的布局。
  • JavaScript:指定网页的行为。

JavaScript 基本特点

JavaScript 是一种属于网络的脚本语言,已经被广泛用于 Web 应用开发,常用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果。通常 JavaScript 脚本是通过嵌入在 HTML 中来实现自身的功能的(就是写在 HTML 页面中的 <script> 标签中)。

JavaScript 的基本特点如下所示:

  • Javascript 是一种解释性脚本语言,代码不进行预编译。
  • Javascript 主要作用是用来向 HTML 页面添加交互行为。
  • Javascript 代码可以直接嵌入 HTML 页面,但写成单独的 .js 文件有利于结构和行为分离。
  • 脚本语言,Javascript 脚本语言同其他语言一样,有它自身的基本数据类型,表达式和算术运算符及程序的基础程序框架。
  • 跨平台特性,JavaScript 脚本语言不依赖于操作系统,仅需要浏览器的支持。在绝大多数浏览器的支持下,可以在 Windows、Android、Linux、Mac、IOS 等平台下运行。

JavaScript 可以做一些什么事情

JavaScript 可以做一些什么事情呢,我们下面简单的介绍一下,可能还没学过 JavaScript 的同学看不懂,不要急,后面我们都会详细的介绍。

  • 直接写入 HTML 输出流,如下所示,我们可以直接在 JavaScript 中写入HTML 代码:
<script type="text/javascript">
  document.write("<h1>侠课岛</h1>");
  document.write("<p>侠课岛欢迎你!</p>");
</script>
  • 对事件作出反应,可以使用 onclick 在HTML元素上绑定事件:
<button type="button" onclick="alert('侠课岛')"> 点击弹出 </button>
  • 修改 HTML 中的内容,例如自定义一个 change() 方法,然后绑定到按钮上:
<body>
  <p id="content">原来的内容</p>
  <button type="button" onclick="change()">点击修改</button>
</body>
<script type="text/javascript">
  function change(){
    document.getElementById('content').innerHTML='新的内容'
  }
</script>
  • JavaScript 还可以实现改变 HTML 图像,例如通过 <img> 标签的 src 属性来改变一张 HTML 图像,如下所示:
<body>
  <button onclick="changeImage()">修改图片</button>
  <div>
    <img id="myImage" src="./img/part1-01.jpg">
  </div>
</body>
<script type="text/javascript">
  function changeImage(){
    element=document.getElementById('myImage');
    if(element.src.match("02")){
      element.src="./img/part1-01.jpg";
    }else{
      element.src="./img/part1-02.jpg";
    }
  }
</script>
  • JavaScript 可以用来改变 HTML 样式,例如:
<p id="style">JavaScript改变HTML样式</p>

//点击之后呈现的效果是:颜色变绿
<button type="button" onclick="document.getElementById('style').style.color='green'">点击</button>
  • 验证输入,例如:
if isNaN(x) {alert("不是数字")};

本节我们基本讲了一下JavaScript是什么,它能做什么,下一节我们讲JavaScript最基本的语法,学习一门语言,我们都要先弄清楚这门语言的基本语言,才好开始编写代码。

.为何学习 JavaScript?

?JavaScript 是 web 开发者必学的三种语言之一:
HTML 定义网页的内容----[制作网页]----简单枯燥
CSS 规定网页的布局和样式—[美化网页]
HTML+CSS—网页—没有动态的网页【1.无动态效果 2.数据没有动态化】
JavaScript 对网页行为进行编程【动态效果,数据动态加载】
2. 什么是JavaScript?
?? 1.javascript和java是完全不同的语言,不论是概念还是设计。
?? 网景----浏览器【Netscape Navigator】----LiveScript-----JavaScript
?? 微软----浏览器[IE]----JScript
…等等
?? ECMA—欧洲计算机厂家协会–ECMA-262标准—ECMAScript
?? 2.JavaScript面向对象的脚本程序设计语言
?? 面向对象—编程思想
?? 脚本程序—依据一定的格式编写的可执行文件【直接运行】
?? 3.JavaScript使用
??1.标记的事件中使用

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<h1>1.标记的事件中使用</h1>
		<input type="button" value="测试Javascript的使用" 
		onclick="alert('欢迎使用Javascript')" />
	</body>
</html>


2.script标记中的使用
?? script–<script>javascript程序</script>
?? 位置–<head>标记中/<body>标记中【最后】

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script type="text/javascript">
			alert("欢迎使用JavaScript!");
		</script>
	</head>
	<body>
		<h1>script标记的中使用</h1>
		<h1>script标记出现在head标记中</h1>
		<input type="button"  value="测试javascript的使用" onclick="test1();" />
	</body>
</html>


<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<h1>script标记的使用</h1>
		<h1>script标记出现在body标记中</h1>
		<input type="button" value="测试JavaScript的使用" onclick="test1()" />
		<script type="text/javascript">
			function test1(){
				alert("欢迎使用javascript!");
			}
		</script>
	</body>
</html>


3.外部脚本—将JavaScript程序编写到独立的文件【.js】,通过<script>标记提供的src属性将独立的文件【.js】,导入到html文件中。
?? 您可以在<head>或<body>中放置外部脚本引用。
?? 格式:<script src=“js 文件路径”></script>
独立的jsWENJIAN 【myscript1.js】
function test1(){
?alert("欢迎使用javascript!”);
}
.js文件

function test1(){
	alert("欢迎使用JavaScript!")
}

html文件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="javascript.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<h1>script外部脚本使用</h1>
		<input type="button"  value="测试JavaScript的使用" onclick="test1();" />
	</body>
</html>


3.JavaScript 输出
JavaScript能够以不同方式“显示”数据:
?? 1.使用window.alert()写入警告框
?? 2.使用document.write()写入HTML输出
?? 3.使用innerHTML写入HTML元素
?? 4.使用console.log()写入浏览器控制台

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<h1>1.使用window.alert()写入警告框</h1>
		<!--
		<script type="text/javascript">
			window.alert("测试window.alert()写入警告框")
		</script>
		-->
		<h1>2.使用document.write()写入HTML输出</h1>
		<!--
		<script type="text/javascript">
			document.write("测试document.write()写入HTML输出")
		</script>
		-->
		<h1>3.使用innerHTML写入HTML元素</h1>
		<p id="p1"></p>
		<!--
		<script type="text/javascript">
			document.getElementById("p1").innerHTML="<font size='7'>测试innerHTML写入HTML元素</font>"
		</script>
		-->
		<h1>4.使用console.log()写入浏览器控制台</h1>
		<script type="text/javascript">
			console.log("console.log()写入浏览器控制台")
		</script>
	</body>
</html>


4.JavaScript 语句
JavaScript 语句由以下构成:
?? 值、运算符、表达式、关键词和注释。
?? document.getElementById(“demo”).innerHTML=“Hello Kitty.”;
“Hello Kitty.”----值
??=— 赋值运算符
?? 关键词–常常通过某个关键词来标识需要执行的 JavaScript 动作


注释–解释说明代码的含义/调试程序【注释的内容不会被执行】
// 单行注释 【保证一行代码被注释掉不会被执行】
/*
多行注释 【保证多行代码被注释掉不会被执行】
// 可以包含单行注释
*/

  <script>
			/*
			//console.log("console.log() 写入浏览器控制台");
			console.log("console.log() 写入浏览器控制台");
			console.log("console.log() 写入浏览器控制台");
console.log("console.log() 写入浏览器控制台");
			*/
		</script>

分号 ; 表示一条javascript语句的结束。
??可以将有分号的语句写在同一行,通常我们都不这么写,出错以后查找不方便,所以一行一句。
JavaScript代码块【{代码块}】
function myFunction(){
??document.getElementById(“demo”).innerHTML=“Hello Kitty.”;
??document.getElementById(“myDIV”).innerHTML=“How are you?”;
}
5.JavaScript 语法
JavaScript 值
JavaScript 语句定义两种类型的值:混合值和变量值。
混合值被称为字面量(literal)— 常量值
写数值有无小数点均可:12.5 1001
写字符串:”zhangsan”
变量值被称为变量[程序运行的最小单位]保存数据值。
需要通过var 关键词 来定义变量
用法1 : var a; //定义变量
??a=1001; //变量赋值
用法2: var b=”hello”;
JavaScript 运算符
JavaScript使用算是运算符(+ - * /)来计算值。
JavaScript使用(=)赋值运算符。
JavaScript使用(> <==>=<=!=)比较运算符。
JavaScript使用(|| && !)逻辑运算符。

JavaScript表达式
表达式是值、变量和运算符的组合,计算结果是值。
100+123【算数表达式】
var b=“hello”; 【赋值表达式】
12>23 【关系表达式】
(12>23)&&(23<12) —【逻辑表达式】

JavaScript 标识符
标识符就是为JavaScript元素【函数,变量,对象…】起名字的字符串。
1.可以由字母、下划线(_)或美元符号($),数字组成,数字不能开头。
2.不能用关键词
3.区分大小写
驼峰式命名规则—首字母大写【FirstName, LastName, MasterCard, InterCity.】
JavaScript 程序员倾向于使用以小写字母开头的驼峰大小写
6. JavaScript 变量
??JavaScript 变量是存储数据值的容器。
??JavaScript 数据类型
??在编程中,文本值被称为字符串。
??JavaScript 可处理多种数据类型,但是现在,我们只关注数值和字符串值。
??字符串被包围在双引号或单引号中。数值不用引号。
??如果把数值放在引号中,会被视作文本字符串。
??true/false 布尔型
??null null型
声明(创建) JavaScript 变量
在 JavaScript 中创建变量被称为“声明”变量。
您可以通过 var 关键词来声明 JavaScript 变量:
var carName;
声明之后,变量是没有值的。(技术上,它的值是 undefined。)我们在使用的变量的时候需要赋予初始值,否则被视为未定义。
通过”=”给变量赋值。
var carName;
carName=”BMW”;

var carName=”BMW”;
一条语句,多个变量
var person=“Bill Gates”, carName=“porsche”, price=15000;

7.JavaScript运算符

JavaScript 使用(=)赋值运算符。
JavaScript 使用算数运算符(+ - * / % ++ --)来计算值。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>变量-运算符-表达式</title>
		<script>
			function  suanshu(){
				//声明变量
				var num1=10;
				var num2=3;
				document.getElementById("h1").innerHTML=num1+"+"+num2+"="+(num1+num2);
				document.getElementById("h2").innerHTML=num1+"-"+num2+"="+(num1-num2);
				document.getElementById("h3").innerHTML=num1+"*"+num2+"="+(num1*num2);
				document.getElementById("h4").innerHTML=num1+"/"+num2+"="+(num1/num2);
				document.getElementById("h5").innerHTML=num1+"%"+num2+"="+(num1%num2);
				// ++ [自动加1]
				// 变量++  [先用后加]
				//num1++;  //10
				//document.getElementById("h6").innerHTML=num1; //11
				// ++变量  [先加后用]
				//++num1;  //11
				//document.getElementById("h6").innerHTML=num1; //11
				// -- [自动减1]
				// 变量-- [先用后减]
				//num1-- ; //10
				//document.getElementById("h6").innerHTML=num1; //9
				//  -- 变量
				--num1;  // 9
				document.getElementById("h6").innerHTML=num1; //9
			}
		</script>
	</head>
	<body>
		<input  type="button"  value="测试算数运算符" onclick="suanshu()"/><br>
		<h1 id="h1"></h1>
		<h1 id="h2"></h1>
		<h1 id="h3"></h1>
		<h1 id="h4"></h1>
		<h1 id="h5"></h1>
		<h1 id="h6"></h1>
	</body>
</html>


JavaScript 使用(> <==>=<=!=)比较运算符运算符。

JavaScript 使用(|| && ! )逻辑运算符运算符。

为一名前端爱好者, 我利用空余时间研究了几个国外网站的源码,发现不管是库,还是业务代码,都会用到了一些比较有意思的API,虽然平时在工作中部分接触过,但是经过这次的研究,觉得很有必要总结一下,毕竟已经2020年了,是时候更新一下技术储备了,本文主要通过实际案例来带大家快速了解以下几个知识点:

  • Observer 原生观察者
  • script标签事件深入 - 移除script标签后事件仍然能执行的原因
  • Proxy/Reflect 自定义事件
  • fileReader API Fullscreen 网页全屏
  • URL API的使用
  • Geolocation 地理位置API的使用
  • Notifications 浏览器原生消息通知
  • Battery Status 设备电量情况

我会对部分API做一些比较有意思的案例,那么开始我们的学习吧~

1. Observer API

Observer是浏览器自带的观察者,它主要提供了Intersection, Mutation, Resize, Performance这四类观察者, 这里笔者重点介绍Intersection Observer.

1.1 Intersection Observer

IntersectionObserver提供了一种异步观察目标元素与其祖先元素交叉状态的方法。当一个IntersectionObserver对象被创建时,其被配置为监听根中一段给定比例的可见区域,并且无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;然而,我们可以在同一个观察者对象中配置监听多个目标元素。

说简单点就是该api可以异步监听目标元素在根元素里的位置变动,并触发响应事件.我们可以利用它来实现更为高效的图片懒加载, 无限滚动以及内容埋点上报等.接下来我们通过一个例子来说明一下它的使用步骤.

// 1.定义观察者及观察回调
const intersectionObserver=new IntersectionObserver((entries, observer)=> {
    entries.forEach(entry=> { 
      console.log(entry)
      // ...一些操作
    }); 
   },
   {
    root: document.querySelector('#root'),
    rootMargin: '0px',
    threshold: 0.5
   }
)
// 2. 定义要观察的目标对象
const target=document.querySelector(“.target”); 
intersectionObserver.observe(target);

以上代码就实现了一个基本的Intersection Observer,虽然已有代码中还体现不出什么实质性功能. 接下来介绍一下代码中使用到的参数的含义: * callback IntersectionObserver实例的第一个参数, 当目标元素与根元素通过阈值 时就会触发该回调.回调中第一个参数是被观察对象列表,一旦被观察对象发生突变就会被移入该列表, 列表中每一项都保留有观察者的位置信息;第二个参数为observer,观察者本身.如下图控制台打印:

其中rootBounds表示根元素的位置信息, boundingClientRect表示目标元素的位置信息,intersectionRect表示叉部分的位置信息, intersectionRatio表示目标元素的可见比例.

  • 配置属性 IntersectionObserver实例的第二个参数,用来配置监听属性,具体有以下三个属性:
    • root 所监听对象的具体祖先元素(element)。如果未传入值或值为null,则默认使用顶级文档的视窗。
    • rootMargin 计算交叉时添加到根(root)边界盒bounding box的矩形偏移量, 可以有效的缩小或扩大根的判定范围从而满足计算需要
    • thresholds 一个包含阈值的列表, 按升序排列, 列表中的每个阈值都是监听对象的交叉区域与边界区域的比率。当监听对象的任何阈值被越过时,都会生成一个通知(Notification)。如果构造器未传入值, 则默认值为0。 以上属性介绍字面上可能很难理解,笔者花几个草图来让大家有个直观的认知:

当我们设置rootMargin为10px时,我们的root会增大影响范围,但目标元素移动到淡红色区域式就会被监听到,当然我们还可以设置rootMargin为负值来减少影响区域.其支持的值为百分比和px,如下:

rootMargin: '10px'
rootMargin: '10%'
rootMargin: '10px 0px 10px 10px'

thresholds可以如下图理解:

由上图所示,当我们设置阈值为[0.25, 0.5]时, 目标元素的25%和50%进入根元素的影响范围时都会触发回调.利用这个特性我们往往可以实现位差动画,或者更根据目标元素的位置变化做不同的交互. 当然Intersection还提供了以下几个方法来控制观察对象: disconnect() 使IntersectionObserver对象停止监听工作 takeRecords() 返回所有观察目标的IntersectionObserverEntry对象数组 * unobserve() 使IntersectionObserver停止监听特定目标元素

了解了使用方法和api之后,我们来看看一个实际应用--实现图片懒加载:

<img src="loading.gif" data-src="absolute.jpg">
<img src="loading.gif" data-src="relative.jpg">
<img src="loading.gif" data-src="fixed.jpg">

<script>
let observerImg=new IntersectionObserver(
(entries, observer)=> { 
    entries.forEach(entry=> {
        // 替换为正式的图片
        entry.target.src=entry.target.dataset.src;
        // 停止监听
        observer.unobserve(entry.target);
      });
    }, 
    {
      root: documennt.getElementById('scrollView'),
      threshold: 0.3
    }
);

document.querySelectorAll('img').forEach(img=> { observerImg.observe(img) });
</script>

以上代码就实现了一个图片懒加载功能, 当图片的30%进入根元素时才加载真实的图片,这又让我想起了之前在某条做广告埋点上报时使用react-lazyload的画面.大家还可以利用它实现无限滚动, H5视差动画等有意思的交互场景.

1.2 Mutation Observer和Resize Observer

Mutation Observer主要用来实现dom变动时的监听,同样也是异步触发,对监听性能非常友好. Resize Observer主要用来监听元素大小的变化,相比于每次窗口变动都触发的window.resize事件, Resize Observer有更好的性能和对dom有更细粒度的控制,它只会在绘制前或布局后触发调用. 以上两个api的使用和Intersection使用非常类似,官方资料也写得很全,大家可以好好研究一下.

2. 移除script标签后事件仍然能执行的原因

这个问题主要是之前有朋友问过我,当时的想法就是简单的认为script内的代码执行完之后以及与dom绑定了,存放在了浏览器内存中,最近查了很多资料发现有一个有点意思的解释,放出来大家可以感受一下:

JavaScript解释器在执行脚本时,是按块来执行的,也就是说浏览器在解析HTML文档流时,如果遇到一个script标签,javascript解释器会等待这个代码块都加载完了,才进行预编译,然后才执行。所以,当开始执行这个代码块的代码时,这个代码段已经被解析完了。这时再从DOM中删去也就不影响代码的执行了。

3. Proxy/Reflect

Proxy/Reflect虽然是es6的api,出现也已经有几年了,但是在项目中用的还是比较少,如果是做底层架构方面的工作,还是建议大家多去使用,毕竟vue/react这种框架源码把这些api玩的如火纯青,还是很有必要掌握一下的。

其实我们认真看mdn的介绍或者阮一峰老师的文章,还是很好理解这些api的用法的,接下来我们详细介绍一下这两个api以及应用场景.

3.1 Proxy

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy在很多场景中都会和Reflect一起使用. 用法也很简单,我们看看Proxy的基本用法:

const obj={
   name: '徐小夕',
   age: '120'
 }
 const proxy=new Proxy(obj, {
   get(target, propKey, receiver) {
    console.log('get:' + propKey)
    return Reflect.get(target, propKey, receiver)
   },
   set(target, propKey, value, receiver) {
    console.log('set:' + propKey)
    return Reflect.set(target, propKey, value, receiver)
   }
 })
 console.log(proxy.name) // get:name 徐小夕
 proxy.work='frontend' // set:work frontend

以上代码拦截了obj对象,并重新定义了读写(get/set)方法,这样我们就可以在访问对象时进行额外的操作了.

Proxy还有apply(拦截 Proxy 实例作为函数调用的操作)和construct(拦截 Proxy 实例作为构造函数调用的操作)等属性可以使用,我们可以在对象操作的不同阶段进行拦截,这里我就不一一样举例了.接下来看看Proxy的实际应用场景. * 实现数组读取负数的索引

我们一般操作数组大多数都是正向操作的,不能通过指定负数来逆向查找数组,如下图:

我们不能通过arr[-1]来拿到数组的尾部元素(字符串同理),这个时候我们就可以用Proxy来实现这一功能,这是我们的结构有点像环状:

这种实现的好处是如果我们想访问数组的最后一个元素时,我们不需要先拿到长度,再通过索引访问了:

// 原始写法
arr[arr.length -1]
// 通过proxy改造后写法
arr[-1]

实现代码如下:

function createArray(...elements) {
  let handler={
    get(target, propKey, receiver) {
      let index=Number(propKey);
      if (index < 0) {
        propKey=String(target.length + index);
      }
      return Reflect.get(target, propKey, receiver);
    }
  };

  let target=[];
  target.push(...elements);
  return new Proxy(target, handler);
}

我们可以发现以上代码使用proxy来代理数组的读取操作,在内部封装了支持负值查找的功能,当然我们也可以不用proxy来实现同样的功能,这里实现参考阮一峰老师的实现. * 利用proxy实现更优雅的校验器

一般我们在做表单校验的时候会写一些if else或者switch判断来实现对不同属性值的校验,同样我们也可以用proxy来优雅的实现它,代码如下:

const formData={
   name: 'xuxi',
   age: 120,
   label: ['react', 'vue', 'node', 'javascript']
 }
 // 校验器
 const validators={
   name(v) {
     // 检验name是否为字符串并且长度是否大于3
     return typeof v==='string' && v.length > 3
   },
   age(v) {
     // 检验age是否为数值
     return typeof v==='number'
   },
   label(v) {
     // 检验label是否为数组并且长度是否大于0
     return Array.isArray(v) && v.length > 0
   }
 }
 // 代理校验对象
 function proxyValidator(target, validator) {
  return new Proxy(target, {
    set(target, propKey, value, receiver) {
      if(target.hasOwnProperty(propKey)) {
        let valid=validator[propKey]
        if(!!valid(value)) {
          return Reflect.set(target, propKey, value, receiver)
        }else {
          // 一些其他错误业务...
          throw Error(`值验证错误${propKey}:${value}`)
        }
      }
    }
  })
 }

有了以上实现模式,我们就可以实现对表单中某个值进行设置时进行校验了,用法如下:

let formObj=proxyValidator(formData, validators)
formObj.name=333;   // Uncaught Error: 值验证错误name:f
formObj.age='ddd'   // Uncaught Error: 值验证错误age:f

以上代码中当设置了不合法的值时,控制台将会剖出错误,如果在实际业务中,我们可以给用户做出适当的提醒. 实现请求拦截和错误上报 实现数据过滤

以上几点笔者在之前的文章中也写过,所以这里不在详细介绍了.大家也可以根据实际情况自己实现更加灵活的拦截操作.当然Proxy提供的API远远不止这几个,我们可以在MDN或者其他渠道了解更多高级用法.

3.2 Reflect

Reflect对象与Proxy对象一样,也是 ES6 为了操作对象而提供的新 API,更多的应用场景是配合proxy一起使用,在上文中已经用到了.可以将Object对象的一些明显属于语言内部的方法放到Reflect对象上,并修改某些Object方法的返回结果. Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。

4. 自定义事件

CustomEvent API是个非常有意思的api, 而且非常实用, 更重要的是学起来非常简单,而且被大部分现代浏览器支持.我们可以让任意dom元素监听和触发自定义事件,只需要如下操作:

// 添加一个适当的事件监听器
dom1.addEventListener("boom", function(e) { something(e.detail.num) })

// 创建并分发事件
var event=new CustomEvent("boom", {"detail":{"num":10}})
dom1.dispatchEvent(event)

我们来看看CustomEvent的参数介绍: type 事件的类型名称,如上面代码中的'boom' CustomEventInit 提供了事件的配置信息,具体有以下几个属性 * bubbles 一个布尔值,表明该事件是否会冒泡 * cancelable 一个布尔值,表明该事件是否可以被取消 * detail 当事件初始化时传递的数据

我们可以通过dispatchEvent来触发自定义事件.其实他的用途有很多,比如创建观察者模式, 实现数据双向绑定, 亦或者在游戏开发中实现打怪掉血,比如下面的例子:


笔者上面画了一个打boss的草图, 现在的场景是两个玩家一起打boss, 我们可以在玩家发动攻击的时候触发dispatch掉血的自定义事件, boss监听到事件后将血量自动扣除, 至于不同角色的伤害值,我们可以存放在detail中,然后通过策略模式去分发伤害.笔者曾今在学校开发的H5游戏时就大量采用类似的模式,还是非常有意思的.

5. fileReader

File API使得我们在浏览器端可以访问文件的数据,比如预览文件,获取文件信息(比如文件名,文件内容,文件大小等), 并且可以在前端实现文件下载(可以借助canvas和 window.URL.revokeObjectURL的一些能力).当然我们还可以实现拖拽上传文件这样高用户体验的操作.接下来我们来看看几个实际例子. * 显示缩略图

function previewFiles(files, previewBox) {
    for (var i=0; i < files.length; i++) {
      var file=files[i];
      var imageType=/^image\//;

      if (!imageType.test(file.type)) {
        continue;
      }

      var img=document.createElement("img");
      previewBox.appendChild(img); // 假设"preview"就是用来显示内容的div

      var reader=new FileReader();
      reader.onload=(function(imgEl) { 
        return function(e) { imgEl.src=e.target.result; }; 
      })(img);
      reader.readAsDataURL(file);
    }
  }

以上代码可以在reviewBox容器中显示已上传好的图片,当然我们还可以基于此来扩展,利用canvas将图片画到canvas上,然后进行图片压缩,最后再把压缩后的图片上传到服务器.这中方式其实目前很多工具型网站都在用,比如在线图片处理网站,提供的批量压缩图片,批处理水印等功能,套路都差不多,感兴趣的朋友可以尝试研究一下. * 封装文件上传组件

这块笔者之前也写过详细的文章,这里就不一一举例了.

6. Fullscreen

全屏API主要是让网页能在电脑屏幕中全屏显示,它允许我们打开或者退出全屏模式,以便我们根据需要进行对应的操作,比如我们常用的网页图形编辑器或者富文本编辑器, 为了让用户专心于内容设计,我们往往提供切换全屏的功能供用户使用.由于全屏API比较简单,这里我们直接上代码:

// 开启全屏
document.documentElement.requestFullscreen();
// 退出全屏
document.exitFullscreen();

以上代码的document.documentElement也可以换成任何一个你想让其全屏的元素.默认情况下我们还可以通过document.fullscreenElement来判断当前页面是否处于全屏状态,来实现屏幕切换的效果.如果是react开发者,我们也可以将其封装成一个自定义hooks来实现与业务相关的全屏切换功能.

7. URL

URL API是URL标准的组成部分,URL标准定义了构成有效统一资源定位符的内容以及访问和操作URL的API。

我们利用URL组件可以做很多有意思的事情.比如我们有个需求需要提取url的参数传给后台,传统的做法是自己写一个方法来解析url字符串,手动返回一个query对象.但是利用URL对象,我们可以很方便的拿到url参数,如下:

let addr=new URL(window.location.href)
let host=addr.host  // 获取主机地址
let path=addr.pathname  // 获取路径名
let user=addr.searchParams.get("user")  // 获取参数为user对应的值

以上代码可知,我们如果将url转化为URL对象,那么我们就可以很方便的通过searchParams提供的api来拿到url参数而无需自己再写一个方法了.

另一方面,如果网站安全性比较高,我们还可以对参数进行自然数排序然后再加密上传给后端.具体代码如下:

function sortMD5WithParameters() {
    let url=new URL(document.location.href);
    url.searchParams.sort();
    let keys=url.searchParams.keys();
    let params={}

    for (let key of keys) {
      let val=url.searchParams.get(key);
      params[key]=val
    };
    // ...md5加密
    return MD5(params)
 }

8. Geolocation

地理位置 API 通过 navigator.geolocation 提供, 这个浏览器API也比较实用, 我们在网站中可以用此方式确定用户的位置信息,从而让网站有不同的展现,增强用户体验.

举几个有意思的例子可以让大家感受一下: 根据不同地区,网站展示不同的主题:

根据用户所在地区,展示不同推荐内容 这一点电商网站或者内容网站用的比较多, 比如用户在新疆,则给他推荐瓜果类广告, 在北京,则给他推荐旅游景点类广告等,虽然实际应用中往往会更复杂,但是也是一种思路.

其实应用远远不止如此,程序员可以发挥想象来实现更有意思的事情,让自己的网站更智能.接下来笔者就基于promise写一段获取用户位置的代码:

function getUserLocation() {
    return new Promise((resolve, reject)=> {
      if (!navigator.geolocation) {
        reject()
      } else {
        navigator.geolocation.getCurrentPosition(success, error);
      }

      function success(position) {
        const latitude=position.coords.latitude;
        const longitude=position.coords.longitude;
        resolve({latitude, longitude})
      }

      function error() {
        reject()
      }
    })
  }

使用方式和结果如下图所示:

我们基于获取到的经纬度调用第三方api(比如百度,高德)就可以获取用户所在为精确位置信息了.

9. Notifications

Notifications API 允许网页或应用程序在系统级别发送在页面外部显示的通知;这样即使应用程序空闲或在后台,Web应用程序也会向用户发送信息。

我们举个实际的例子,比如我们网站内容有更新,通知用户,效果如下:

相关代码如下:

Notification.requestPermission( function(status) {
  console.log(status); // 仅当值为 "granted" 时显示通知
  var n=new Notification("趣谈前端", {body: "从零搭建一个CMS全栈项目"}); // 显示通知
});

当然浏览器的Notification还给我们提供了4个事件触发api方便我们做更全面的控制: onshow 当通知被显示给用户时触发 (已废弃, 但部分浏览器仍然能用) onclick 当用户点击通知时触发 onclose 当通知被关闭时触发(已废弃, 但部分浏览器仍然能用) onerror 当通知发生错误的时候触发

有了这样的事件监听,我们就可以控制当用户点击通知时, 跳转到对应的页面或者执行相关的业务逻辑.如下代码所示:

Notification.requestPermission( function(status) {
  console.log(status); // 仅当值为 "granted" 时显示通知
  var n=new Notification("趣谈前端", {body: "从零搭建一个CMS全栈项目"}); // 显示通知
      n.onshow=function () { 
        // 消息显示时执行的逻辑
        console.log('show') 
      }
      n.onclick=function () { 
        // 消息被点击时执行的逻辑
        history.push('/detail/1232432')
      }
      n.onclose=function () { 
        // 消息关闭时执行的逻辑
        console.log('close')
      }
});

当然我们在使用前需要获取权限,方式也很简单,大家可以在mdn上学习了解.

10. Battery Status

Battery Status API提供了有关系统充电级别的信息并提供了通过电池等级或者充电状态的改变提醒用户的事件。 这个可以在设备电量低的时候调整应用的资源使用状态,或者在电池用尽前保存应用中的修改以防数据丢失。

之前的版本中Battery Status API提供了几个事件监听函数来监听电量的变化以及监听设备是否充电,但是笔者看文档时这些api都已经废弃,如下: chargingchange 监听设别是否充电 levelchange 监听电量充电等级 chargingtimechange 充电时间变化 dischargingtimechange 放电时间变化

虽然以上几个看似有用的api已经被弃用,但是笔者亲测谷歌还是可以正常使用的,但是为了让自己代码更可靠,我们可以用其他方式代替,比如用定时器定期去检测电量情况,进而对用户做出不同的提醒.

接下来我们看看基本的用法:

navigator.getBattery().then(function(battery) {
  console.log("是否在充电? " + (battery.charging ? "是" : "否"));
  console.log("电量等级: " + battery.level * 100 + "%");
  console.log("充电时间: " + battery.chargingTime + " s");
  console.log("放电时间: " + battery.dischargingTime + "s");
});

我们可以通过getBattery拿到设备电池信息,这个api非常有用,比如我们可以在用户电量不足时禁用网站动画或者停用一些耗时任务,亦或者是对用户做适当的提醒,改变网站颜色等,对于webapp中播放视频或者直播时,我们也可以用css画一个电量条,当电量告急时提醒用户.作为一个优秀的网站体验师,这一块还是不容忽视的.

参考文献

  • ECMAScript 6 入门 - 阮一峰
  • MDN web English docs