一文学会JavaScript

定义:

JavaScript 是一种脚本,一门编程语言,它可以在网页上实现复杂的功能,网页展现给你的不再是简单的静态信息,而是实时的内容更新,交互式的地图,2D/3D 动画,滚动播放的视频等等。

  • HTML是一种标记语言,用来结构化我们的网页内容并赋予内容含义,例如定义段落、标题和数据表,或在页面中嵌入图片和视频。
  • CSS 是一种样式规则语言,可将样式应用于 HTML 内容,例如设置背景颜色和字体,在多个列中布局内容。
  • JavaScript 是一种脚本语言,可以用来创建动态更新的内容,控制多媒体,制作图像动画,还有很多。

简单例子

<p>玩家 1:小明</p>
p {
  font-family: sans-serif, '黑体';
  letter-spacing: 1px;
  text-transform: uppercase;
  text-align: center;
  border: 2px solid rgba(0, 0, 200, 0.6);
  background: rgba(0, 0, 200, 0.3);
  color: rgba(0, 0, 200, 0.6);
  box-shadow: 1px 1px 2px rgba(0, 0, 200, 0.4);
  border-radius: 10px;
  padding: 3px 10px;
  display: inline-block;
  cursor: pointer;
}
const para = document.querySelector('p');

para.addEventListener('click', updateName);

function updateName() {
  let name = prompt('输入一个新的名字:');
  para.textContent = '玩家 1:' + name;
}

js调用策略:

要让脚本调用的时机符合预期,需要解决一系列的问题。这里看似简单,实际大有文章。最常见的问题就是:HTML 元素是按其在页面中出现的次序调用的,如果用 JavaScript 来管理页面上的元素(更精确的说法是使用 文档对象模型 DOM),若 JavaScript 加载于欲操作的 HTML 元素之前,则代码将出错。

<!-- async它告知浏览器在遇到 <script> 元素时不要中断后续 HTML 内容的加载。-->
<script src="script.js" async></script>

async 只能用于外部脚本,因此不适用于“内部”示例,内部示例:

//这是一个事件监听器,它监听浏览器的 "DOMContentLoaded" 事件,即 HTML 文档体加载、解释完毕事件。事件触发时将调用 " . . ." 处的代码,从而避免了错误发
document.addEventListener("DOMContentLoaded", function() {
  . . .
});

defer

配合async使用。可以指定脚本的加载和运行顺序。当然,当若干个脚本无关联和先后顺序时,只用async即可。 添加 defer 属性的脚本将按照在页面中出现的顺序加载 。

<script defer src="js/vendor/jquery.js"></script>

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

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

猜数字例子

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">

    <title>猜数字游戏</title>

    <style>
      html {
        font-family: sans-serif;
      }

      body {
        width: 50%;
        max-width: 800px;
        min-width: 480px;
        margin: 0 auto;
      }

      .lastResult {
        color: white;
        padding: 3px;
      }
    </style>
  </head>

  <body>
    <h1>猜数字游戏</h1>

    <p>我刚才随机选定了一个100以内的自然数。看你能否在 10 次以内猜中它。每次我都会告诉你所猜的结果是高了还是低了。</p>

    <div class="form">
      <label for="guessField">请猜数: </label>
      <input type="text" id="guessField" class="guessField">
      <input type="submit" value="确定" class="guessSubmit">
    </div>

    <div class="resultParas">
      <p class="guesses"></p>
      <p class="lastResult"></p>
      <p class="lowOrHi"></p>
    </div>

    <script>

      // 开始编写 JavaScript 代码

    </script>
  </body>
</html>
let randomNumber = Math.floor(Math.random() * 100) + 1;

const guesses = document.querySelector('.guesses');
const lastResult = document.querySelector('.lastResult');
const lowOrHi = document.querySelector('.lowOrHi');

const guessSubmit = document.querySelector('.guessSubmit');
const guessField = document.querySelector('.guessField');

let guessCount = 1;
let resetButton;

function checkGuess() {
  let userGuess = Number(guessField.value);
  if (guessCount === 1) {
    guesses.textContent = '上次猜的数:';
  }
  guesses.textContent += userGuess + ' ';

  if (userGuess === randomNumber) {
    lastResult.textContent = '恭喜你!猜对了';
    lastResult.style.backgroundColor = 'green';
    lowOrHi.textContent = '';
    setGameOver();
  } else if (guessCount === 10) {
    lastResult.textContent = '!!!GAME OVER!!!';
    setGameOver();
  } else {
    lastResult.textContent = '你猜错了!';
    lastResult.style.backgroundColor = 'red';
    if(userGuess < randomNumber) {
      lowOrHi.textContent = '你猜低了!';
    } else if(userGuess > randomNumber) {
      lowOrHi.textContent = '你猜高了';
    }
  }

  guessCount++;
  guessField.value = '';
  guessField.focus();
}

guessSubmit.addEventListener('click', checkGuess);

function setGameOver() {
  guessField.disabled = true;
  guessSubmit.disabled = true;
  resetButton = document.createElement('button');
  resetButton.textContent = '开始新游戏';
  document.body.appendChild(resetButton);
  resetButton.addEventListener('click', resetGame);
}

function resetGame() {
  guessCount = 1;

  const resetParas = document.querySelectorAll('.resultParas p');
  for (let i = 0 ; i < resetParas.length; i++) {
    resetParas[i].textContent = '';
  }

  resetButton.parentNode.removeChild(resetButton);

  guessField.disabled = false;
  guessSubmit.disabled = false;
  guessField.value = '';
    //这一行通过 focus() (en-US) 方法让光标在页面加载完毕时自动放置于 <input> 输入框内,
  guessField.focus();

  lastResult.style.backgroundColor = 'white';

  randomNumber = Math.floor(Math.random() * 100) + 1;
}

学会调试js和使用js就控制台

变量

声明变量

let myName;
var myAge;

var和let的区别:

  1. 首先,如果你编写一个声明并初始化变量的多行 JavaScript 程序,你可以在初始化一个变量之后用 var 声明它,它仍然可以工作 .这叫做变量提升。 但提升操作不再适用于 let 。如果将上面例子中的 var 替换成 let 将不起作用并引起一个错误

    myName = 'Chris';
    
    function logName() {
      console.log(myName);
    }
    
    logName();
    
    var myName;
    
  2. 其次,当你使用 var 时,可以根据需要多次声明相同名称的变量,但是 let 不能。以下将有效:

而let会报错

var myName = 'Chris';
var myName = 'Bob';

总而言之,使用let!!!

变量类型

Number

你可以在变量中存储数字,不论这些数字是像 30(也叫整数)这样,或者像 2.456 这样的小数(也叫做浮点数)。与其他编程语言不同,在 JavaScript 中你不需要声明一个变量的类型。当你给一个变量数字赋值时,不需要用引号括起来。

String

字符串是文本的一部分。当你给一个变量赋值为字符串时,你需要用单引号或者双引号把值给包起来,否则 JavaScript 将会把这个字符串值理解成别的变量名。

Boolean

Boolean 的值有 2 种:true 或 false。它们通常被用于在适当的代码之后,测试条件是否成立.

Array

数组是一个单个对象,其中包含很多值,方括号括起来,并用逗号分隔。尝试在您的控制台输入以下行:

let myNameArray = ['Chris', 'Bob', 'Jim'];
let myNumberArray = [10,15,40];

当数组被定义后,您可以使用如下所示的语法来访问各自的值,例如下行:

myNameArray[0]; // should return 'Chris'
myNumberArray[2]; // should return 40

Object

在编程中,对象是现实生活中的模型的一种代码结构。您可以有一个简单的对象,代表一个停车场,并包含有关其宽度和长度的信息,或者您可以有一个代表一个人的对象,并包含有关他们的名字,身高,体重,他们说什么语言,如何说 你好,他们,等等。

let dog = { name : 'Spot', breed : 'Dalmatian' };
dog.name

数字和操作符

无论时整型、浮点、双精度,typeof运算符返回其都是Number类型

算数运算符

和java一样,除了:

**,幂运算

===,等于

!==,不等于

字符串

转义字符

let bigmouth = 'I\'ve got no right to take my place...';
bigmouth;

数字字符串转换

let myString = '123';
let myNum = Number(myString);
typeof myNum;

let myNum = 123;
let myString = myNum.toString();
typeof myString;

api

let browserType = 'mozilla';
browserType.length;
//可以使用方括号表示法返回字符串中的任何字符 
browserType[0];
//个较小的字符串是否存在于一个较大的字符串中
browserType.indexOf('zilla');
//提取
browserType.slice(0,3);
//大小写转换
let radData = 'My NaMe Is MuD';
radData.toLowerCase();
radData.toUpperCase();
//替换
browserType = browserType.replace('moz','van');

数组

创建数组

let shopping = ['bread', 'milk', 'cheese', 'hummus', 'noodles'];
shopping;

let sequence = [1, 1, 2, 3, 5, 8, 13];
let random = ['tree', 795, [0, 1, 2]];

访问修改数组

shopping[0];
// returns "bread"
shopping[0] = 'tahini';
shopping;
// shopping will now return [ "tahini", "milk", "cheese", "hummus", "noodles" ]

api

sequence.length;
// should return 7

let sequence = [1, 1, 2, 3, 5, 8, 13];
for (let i = 0; i < sequence.length; i++) {
  console.log(sequence[i]);
}

//字符串数组转化
let myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';
let myArray = myData.split(',');
myArray;
myArray.length;
myArray[0]; // the first item in the array
myArray[1]; // the second item in the array
myArray[myArray.length-1]; // the last item in the array

//数组转化为字符串
//方法1
let myNewString = myArray.join(',');
myNewString;
//方法2
let dogNames = ["Rocket","Flash","Bella","Slugger"];
dogNames.toString(); //Rocket,Flash,Bella,Slugger


//push 添加一个或多个要添加到数组末尾的元素
myArray.push('Cardiff');
myArray;
myArray.push('Bradford', 'Brighton');
myArray;
//数组中删除最后一个元素
myArray.pop();
//方法调用完成时,将返回已删除的项目
let removedItem = myArray.pop();
myArray;
removedItem;

//unshift shift功能上与 push() 和 pop() 完全相同,只是它们分别作用于数组的开始,而不是结尾。

函数

内置函数:Math.random、myArray.join(’ ')、myText.replace(‘source’,‘target’)等等都是内置函数

当然也可以自定义函数

function a(){

}

匿名函数

//通常将匿名函数与事件处理程序一起使用
function() {
  alert('hello');
}
var myButton = document.querySelector('button');

myButton.onclick = function() {
  alert('hello');
}

//匿名函数的另外一种使用:以将匿名函数分配为变量的值
var myGreeting = function() {
  alert('hello');
}
myGreeting();

事件

事件是您在编程时系统内发生的动作或者发生的事情,系统响应事件后,如果需要,您可以某种方式对事件做出回应。例如:如果用户在网页上单击一个按钮,您可能想通过显示一个信息框来响应这个动作。 事件还有可能是:

  • 用户在某个元素上点击鼠标或悬停光标。
  • 用户在键盘中按下某个按键。
  • 用户调整浏览器的大小或者关闭浏览器窗口。
  • 一个网页停止加载。
  • 提交表单。
  • 播放、暂停、关闭视频。
  • 发生错误。

onclick事件

<button>Change color</button>
/**
我们使用 btn 变量存储 button,并使用了Document.querySelector() 函数。我们也定义了一个返回随机数字的函数。代码第三部分就是事件处理器。btn变量指向 button 元素,在 button 这种对象上可触发一系列的事件,因此也就可以使用事件处理器。我们通过将一个匿名函数(这个赋值函数包括生成随机色并赋值给背景色的代码)赋值给“点击”事件处理器参数,监听“点击”这个事件
*/
const btn = document.querySelector('button');

function random(number) {
  return Math.floor(Math.random()*(number+1));
}

btn.onclick = function() {
  const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  document.body.style.backgroundColor = rndCol;
}

常用的事件

  • btn.onfocus及btn.onblur — 颜色将于按钮被置于焦点或解除焦点时改变(尝试使用 Tab 移动至按钮上,然后再移开)。这些通常用于显示有关如何在置于焦点时填写表单字段的信息,或者如果表单字段刚刚填入不正确的值,则显示错误消息。
  • btn.ondblclick — 颜色将仅于按钮被双击时改变。
    window.onkeypress, window.onkeydown, window.onkeyup — 当按钮被按下时颜色会发生改变。keypress 指的是通俗意义上的按下按钮 (按下并松开), 而 keydown 和 keyup 指的是按键动作的一部分,分别指按下和松开。注意如果你将事件处理器添加到按钮本身,它将不会工作 — 我们只能将它添加到代表整个浏览器窗口的 window对象中。
  • btn.onmouseover 和 btn.onmouseout — 颜色将会在鼠标移入按钮上方时发生改变,或者当它从按钮移出时。

新的触发方式

const btn = document.querySelector('button');

function bgChange() {
  const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  document.body.style.backgroundColor = rndCol;
}

btn.addEventListener('click', bgChange);

//这种方式的优点就是
//1.可以移除
btn.removeEventListener('click', bgChange);
//同一监听绑定多个处理器
//myElement.onclick = functionA;
//myElement.onclick = functionB; 老方法会覆盖

myElement.addEventListener('click', functionA);
myElement.addEventListener('click', functionB);

事件对象

有时候在事件处理函数内部,您可能会看到一个固定指定名称的参数,例如eventevt或简单的e。这被称为事件对象,它被自动传递给事件处理函数,以提供额外的功能和信息
例子:

//在这里,您可以看到我们在函数中包括一个事件对象e,并在函数中设置背景颜色样式在e.target上 - 它指的是按钮本身。事件对象 e 的target属性始终是事件刚刚发生的元素的引用。
function bgChange(e) {
  const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  e.target.style.backgroundColor = rndCol;
  console.log(e);
}

btn.addEventListener('click', bgChange);

事件对象的好处:

//使用 JavaScript 创建了 16 个<div>元素。接着我们使用 document.querySelectorAll()选择全部的元素,然后遍历每一个,为每一个元素都添加一个onclick单击事件,每当它们点击时就会为背景添加一个随机颜色。
const divs = document.querySelectorAll('div');

for (let i = 0; i < divs.length; i++) {
  divs[i].onclick = function(e) {
    e.target.style.backgroundColor = bgChange();
  }
}

事件冒泡和捕捉

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Show video box example</title>
    <style>
      div {
        position: absolute;
        top: 50%;
        transform: translate(-50%,-50%);
        width: 480px;
        height: 380px;
        border-radius: 10px;
        background-color: #eee;
        background-image: linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,0.1));
      }

      .hidden {
        left: -50%;
      }

      .showing {
        left: 50%;
      }

      div video {
        display: block;
        width: 400px;
        margin: 40px auto;
      }

    </style>
  </head>
  <body>
    <button>Display video</button>

    <div class="hidden">
      <video>
        <source src="rabbit320.mp4" type="video/mp4">
        <source src="rabbit320.webm" type="video/webm">
        <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p>
      </video>
    </div>

    <script>

      const btn = document.querySelector('button');
      const videoBox = document.querySelector('div');

      function displayVideo() {
        if (videoBox.getAttribute('class') === 'hidden') {
          videoBox.setAttribute('class','showing');
        }
      }

      btn.addEventListener('click', displayVideo);

      videoBox.addEventListener('click', () => videoBox.setAttribute('class', 'hidden'));

      const video = document.querySelector('video');

      video.addEventListener('click', () => video.play());

    </script>
  </body>
</html>

在该案例中,点击按钮视频隐藏。点击最外层div视频隐藏。点击视频,视频播放。

bug:因为video是嵌套在div里面的,两者都绑定隔离onclick事件,所以点击视频的时候视频播放的同时会触发div的onclick事件,导致视频隐藏。

捕获

当一个事件发生在具有父元素的元素上 (例如,在我们的例子中是``元素) 时,现代浏览器运行两个不同的阶段 - 捕获阶段和冒泡阶段。在捕获阶段:

  • 浏览器检查元素的最外层祖先``,是否在捕获阶段中注册了一个onclick事件处理程序,如果是,则运行它。
  • 然后,它移动到``中单击元素的下一个祖先元素,并执行相同的操作,然后是单击元素再下一个祖先元素,依此类推,直到到达实际点击的元素。
冒泡:
  • 浏览器检查实际点击的元素是否在冒泡阶段中注册了一个onclick事件处理程序,如果是,则运行它
  • 然后它移动到下一个直接的祖先元素,并做同样的事情,然后是下一个,等等,直到它到达``元素。

在现代浏览器中,默认情况下,所有事件处理程序都在冒泡阶段进行注册

stopPropagation()

当在事件对象上调用该函数时,它只会让当前事件处理程序运行,但事件不会在冒泡链上进一步扩大,因此将不会有更多事件处理器被运行 (不会向上冒泡)。

video.onclick = function(e) {
  e.stopPropagation();
  video.play();
};
事件委托

冒泡还允许我们利用事件委托——这个概念依赖于这样一个事实,如果你想要在大量子元素中单击任何一个都可以运行一段代码,您可以将事件监听器设置在其父节点上,并让子节点上发生的事件冒泡到父节点上,而不是每个子节点单独设置事件监听器。

一个很好的例子是一系列列表项,如果你想让每个列表项被点击时弹出一条信息,您可以将click单击事件监听器设置在父元素上,这样事件就会从列表项冒泡到其父元素上。

<ul id="parent-list">
	<li id="post-1">Item 1</li>
	<li id="post-2">Item 2</li>
	<li id="post-3">Item 3</li>
	<li id="post-4">Item 4</li>
	<li id="post-5">Item 5</li>
	<li id="post-6">Item 6</li>
</ul>
// Get the element, add a click listener...
document.getElementById("parent-list").addEventListener("click", function(e) {
	// e.target is the clicked element!
	// If it was a list item
	if(e.target && e.target.nodeName == "LI") {
		// List item found!  Output the ID!
		console.log("List item ", e.target.id.replace("post-", ""), " was clicked!");
	}
});

对象

定义

key:value的类似json格式定义对象

var person = {
  name : ['Bob', 'Smith'],
  age : 32,
  gender : 'male',
  interests : ['music', 'skiing'],
  bio : function() {
    alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
  },
  greeting: function() {
    alert('Hi! I\'m ' + this.name[0] + '.');
  }
};

属性取值、赋值

//取值
person.age
person.interests[1]
person.bio()
//赋值
name : {
  first : 'Bob',
  last : 'Smith'
}
//取值
person.age
person.name.first
//取值
person['age']
person['name']['first']

document

你正在使用Document实例上可用的方法。每个页面在加载完毕后,会有一个 Document 的实例被创建,叫做 document,它代表了整个页面的结构,内容和一些功能,比如页面的 URL。同样的,这意味 document 有一些可用的方法和属性。

var myDiv = document.createElement('div');
var myVideo = document.querySelector('video');

原型

JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。

准确地说,这些属性和方法定义在 Object 的构造器函数 (constructor functions) 之上的prototype属性上,而非对象实例本身。

在传统的 OOP 中,首先定义“类”,此后创建对象实例时,类中定义的所有属性和方法都被复制到实例中。在 JavaScript 中并不如此复制——而是在对象实例和它的构造器之间建立一个链接(它是__proto__属性,是从构造函数的prototype属性派生的),之后通过上溯原型链,在构造器中找到这些属性和方法。

实例

每个函数都有一个特殊的属性叫作原型(prototype)
function doSomething(){}
console.log( doSomething.prototype );
// It does not matter how you declare the function, a
//  function in javascript will always have a default
//  prototype property.
var doSomething = function(){};
console.log( doSomething.prototype );

输出:

{
    constructor: ƒ doSomething(),
    __proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        valueOf: ƒ valueOf()
    }
}
增加原型属性
function doSomething(){}
doSomething.prototype.foo = "bar";
console.log( doSomething.prototype );

输出:

{
    foo: "bar",
    constructor: ƒ doSomething(),
    __proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        valueOf: ƒ valueOf()
    }
}

new实例化对象
function doSomething(){}
doSomething.prototype.foo = "bar"; // add a property onto the prototype
var doSomeInstancing = new doSomething();
doSomeInstancing.prop = "some value"; // add a property onto the object
console.log( doSomeInstancing );

输出:

{
    prop: "some value",
    __proto__: {
        foo: "bar",
        constructor: ƒ doSomething(),
        __proto__: {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            valueOf: ƒ valueOf()
        }
    }
}

JSON

  • parse(): 以文本字符串形式接受 JSON 对象作为参数,并返回相应的对象。
  • stringify(): 接收一个对象作为参数,返回一个对应的 JSON 字符串。
request.open('GET', requestURL);
request.responseType = 'text'; // now we're getting a string!
request.send();

request.onload = function() {
  var superHeroesText = request.response; // get the string from the response
  var superHeroes = JSON.parse(superHeroesText); // convert it to an object
  populateHeader(superHeroes);
  showHeroes(superHeroes);
}

var myJSON = { "name" : "Chris", "age" : "38" };
myJSON
var myString = JSON.stringify(myJSON);
myString

异步

异步编程技术使你的程序可以在执行一个可能长期运行的任务的同时继续对其他事件做出反应而不必等待任务完成。

XMLHttpRequest

<button id="xhr">点击发起请求</button>
<button id="reload">重载</button>

<pre readonly class="event-log"></pre>

const log = document.querySelector('.event-log');
document.querySelector('#xhr').addEventListener('click', () => {
  log.textContent = '';
  const xhr = new XMLHttpRequest();
  xhr.addEventListener('loadend', () => {
    log.textContent = `${log.textContent}完成!状态码:${xhr.status}`;
  });
  xhr.open('GET', 'https://raw.githubusercontent.com/mdn/content/main/files/en-us/_wikihistory.json');
  xhr.send();
  log.textContent = `${log.textContent}请求已发起\n`;});
document.querySelector('#reload').addEventListener('click', () => {
  log.textContent = '';
  document.location.reload();
});

promise

  1. 调用 fetch() API,并将返回值赋给 fetchPromise 变量。
  2. 紧接着,输出 fetchPromise 变量,输出结果应该像这样:Promise { : "pending" }。这告诉我们有一个 Promise 对象,它有一个 state属性,值是 "pending""pending" 状态意味着操作仍在进行中。
  3. 将一个处理函数传递给 Promise 的 then() 方法。当(如果)获取操作成功时,Promise 将调用我们的处理函数,传入一个包含服务器的响应的 Response 对象。
  4. 输出一条信息,说明我们已经发送了这个请求。
const fetchPromise = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');

console.log(fetchPromise);

fetchPromise.then( response => {
  console.log(`已收到响应:${response.status}`);
});

console.log("已发送请求……");

输出:

Promise { <state>: "pending" }
已发送请求……
已收到响应:200
链式使用

在你通过 fetch() API 得到一个 Response 对象的时候,你需要调用另一个函数来获取响应数据。这次,我们想获得JSON格式的响应数据,所以我们会调用 Response 对象的 json() 方法。事实上,json() 也是异步的,因此我们必须连续调用两个异步函数。

const fetchPromise = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');

fetchPromise.then( response => {
  const jsonPromise = response.json();
  jsonPromise.then( json => {
    console.log(json[0].name);
  });
});

//这样写容易理解
fetchPromise
  .then( response => {
    if (!response.ok) {
      throw new Error(`HTTP error: ${response.status}`);
    }
    return response.json();
  })
  .then( json => {
    console.log(json[0].name);
  });

错误捕获

Promise 对象提供了一个 catch() 方法来支持错误处理。这很像 then():你调用它并传入一个处理函数。然后,当异步操作成功时,传递给 then() 的处理函数被调用,而当异步操作失败时,传递给 catch() 的处理函数被调用。

如果将 catch() 添加到 Promise 链的末尾,它就可以在任何异步函数失败时被调用。于是,我们就可以将一个操作实现为几个连续的异步函数调用,并在一个地方处理所有错误。

const fetchPromise = fetch('bad-scheme://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');

fetchPromise
  .then( response => {
    if (!response.ok) {
      throw new Error(`HTTP 请求错误:${response.status}`);
    }
    return response.json();
  })
  .then( json => {
    console.log(json[0].name);
  })
  .catch( error => {
    console.error(`无法获取产品列表:${error}`);
  });

三种状态:
  • 待定(pending):初始状态,既没有被兑现,也没有被拒绝。这是调用 fetch() 返回 Promise 时的状态,此时请求还在进行中。
  • 已兑现(fulfilled):意味着操作成功完成。当 Promise 完成时,它的 then() 处理函数被调用。
  • 已拒绝(rejected):意味着操作失败。当一个 Promise 失败时,它的 catch() 处理函数被调用。
合并:

需要多个promise都得实现,但是他们互不依赖, 在这种情况下,将它们一起启动然后在它们全部被兑现后得到通知会更有效率。这里需要 Promise.all() 方法 。 它接收一个 Promise 数组,并返回一个单一的 Promise。

const fetchPromise1 = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
const fetchPromise2 = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found');
const fetchPromise3 = fetch('https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json');

Promise.all([fetchPromise1, fetchPromise2, fetchPromise3])
  .then( responses => {
    for (const response of responses) {
      console.log(`${response.url}${response.status}`);
    }
  })
  .catch( error => {
    console.error(`获取失败:${error}`)
  });

https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json:200
https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found:404
https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json:200

你可能需要等待一组 Promise 中的某一个 Promise 的执行,而不关心是哪一个。在这种情况下,你需要 Promise.any()。这就像 Promise.all(),不过在 Promise 数组中的任何一个被兑现时它就会被兑现,如果所有的 Promise 都被拒绝,它也会被拒绝 。

const fetchPromise1 = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
const fetchPromise2 = fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/not-found');
const fetchPromise3 = fetch('https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json');

Promise.any([fetchPromise1, fetchPromise2, fetchPromise3])
  .then( response => {
    console.log(`${response.url}${response.status}`);
  })
  .catch( error => {
    console.error(`获取失败:${error}`)
  });

async和await

在异步函数中,你可以在调用一个返回 Promise 的函数之前使用 await 关键字。这使得代码在该点上等待,直到 Promise 被完成,这时 Promise 的响应被当作返回值,或者被拒绝的响应被作为错误抛出。

这里我们调用 await fetch(),我们的调用者得到的并不是 Promise,而是一个完整的 Response 对象,就好像 fetch() 是一个同步函数一样。

async function fetchProducts() {
  try {
    // 在这一行之后,我们的函数将等待 `fetch()` 调用完成
    // 调用 `fetch()` 将返回一个“响应”或抛出一个错误
    const response = await fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
    if (!response.ok) {
      throw new Error(`HTTP 请求错误:${response.status}`);
    }
    // 在这一行之后,我们的函数将等待 `response.json()` 的调用完成
    // `response.json()` 调用将返回 JSON 对象或抛出一个错误
    const json = await response.json();
    console.log(json[0].name);
  }
  catch(error) {
    console.error(`无法获取产品列表:${error}`);
  }
}

fetchProducts();

返回的只能是Promise对象

async function fetchProducts() {
  try {
    const response = await fetch('https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json');
    if (!response.ok) {
      throw new Error(`HTTP 请求错误:${response.status}`);
    }
    const json = await response.json();
    return json;
  }
  catch(error) {
    console.error(`无法获取产品列表:${error}`);
  }
}

const jsonPromise = fetchProducts();
jsonPromise.then((json) => console.log(json[0].name));

自己实现

**setTimeout()**延迟执行

<button id="set-alarm">Set alarm</button>
<div id="output"></div>

const output = document.querySelector('#output');
const button = document.querySelector('#set-alarm');

function setAlarm() {
  window.setTimeout(() => {
    output.textContent = 'Wake up!';
  }, 1000);
}

button.addEventListener('click', setAlarm);

Promise构造

  • 检查 delay(延迟)是否为负数,如果是的话就抛出一个错误。
  • 调用 window.setTimeout(),传递一个回调函数和 delay(延迟)。当计时器过期时回调会被调用,在回调函数内,我们调用了 resolve,并且传递了 "Wake up!" 消息。
function alarm(person, delay) {
  return new Promise((resolve, reject) => {
    if (delay < 0) {
      throw new Error('Alarm delay must not be negative');
    }
    window.setTimeout(() => {
      resolve(`Wake up, ${person}!`);
    }, delay);
  });
}

具体例子:

<body>
        
            <div>
  <label for="name">Name:</label>
  <input type="text" id="name" name="name" size="4" value="Matilda">
</div>
<div>
  <label for="delay">Delay:</label>
  <input type="text" id="delay" name="delay" size="4" value="1000">
</div>
<button id="set-alarm">Set alarm</button>
<div id="output"></div>

        
        
            <script>
                const name = document.querySelector('#name');
const delay = document.querySelector('#delay');
const button = document.querySelector('#set-alarm');
const output = document.querySelector('#output');

function alarm(person, delay) {
  return new Promise((resolve, reject) => {
    if (delay < 0) {
      throw new Error('Alarm delay must not be negative');
    }
    window.setTimeout(() => {
      resolve(`Wake up, ${person}!`);
    }, delay);
  });
}

button.addEventListener('click', () => {
  alarm(name.value, delay.value)
    .then(message => output.textContent = message)
    .catch(error => output.textContent = `Couldn't set alarm: ${error}`);
});

            </script>
        
    
</body>

workers

它使您能够在单独执行 线程 中运行一些任务。 你的主代码和你的 worker 代码永远不能直接访问彼此的变量。Workers 和主代码运行在完全分离的环境中,只有通过相互发送消息来进行交互。特别是,这意味着 workers 不能访问 DOM(窗口、文档、页面元素等等)。

有三种不同类型的 workers:

  • dedicated workers
  • shared workers
  • service workers
具体的例子:

生成质数

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="main.js" defer></script>
    <link href="style.css"rel="stylesheet">
  </head>

  <body>

    <label for="quota">Number of primes:</label>
    <input type="text" id="quota" name="quota" value="10">

    <button id="generate">Generate primes</button>
    <button id="reload">Reload</button>

    <textarea id="user-input" rows="5" cols="62">Try typing in here immediately after pressing "Generate primes"</textarea>

    <div id="output"></div>

  </body>

</html>

// 在 "generate.js" 中创建一个新的 worker
const worker = new Worker('./generate.js');

// 当用户点击 "Generate primes" 时,给 worker 发送一条消息。
// 消息中的 command 属性是 "generate", 还包含另外一个属性 "quota",即要生成的质数。
document.querySelector('#generate').addEventListener('click', () => {
  const quota = document.querySelector('#quota').value;
  worker.postMessage({
    command: 'generate',
    quota: quota
  });
});

// 当 worker 给主线程回发一条消息时,为用户更新 output 框,包含生成的质数(从 message 中获取)。
worker.addEventListener('message', message => {
  document.querySelector('#output').textContent = `Finished generating ${message.data} primes!`;
});

document.querySelector('#reload').addEventListener('click', () => {
  document.querySelector('#user-input').value = 'Try typing in here immediately after pressing "Generate primes"';
  document.location.reload();
});


// 监听主线程中的消息。
// 如果消息中的 command 是 "generate",则调用 `generatePrimse()`
addEventListener("message", message => {
  if (message.data.command === 'generate') {
    generatePrimes(message.data.quota);
  }
});

// 生成质数 (非常低效)
function generatePrimes(quota) {

  function isPrime(n) {
    for (let c = 2; c <= Math.sqrt(n); ++c) {
      if (n % c === 0) {
          return false;
       }
    }
    return true;
  }

  const primes = [];
  const maximum = 1000000;

  while (primes.length < quota) {
    const candidate = Math.floor(Math.random() * (maximum + 1));
    if (isPrime(candidate)) {
      primes.push(candidate);
    }
  }

  // 完成后给主线程发送一条包含我们生成的质数数量的消息消息。
  postMessage(primes.length);
}

Ajax

//每次选择相应的文件时,展示相应的内容
const verseChoose = document.querySelector('select');
const poemDisplay = document.querySelector('pre');

verseChoose.onchange = function() {
  const verse = verseChoose.value;
  updateDisplay(verse);
};

function updateDisplay(verse) {
    //文件名为Verse 1,需要转化为verse1.txt
	verse = verse.replace(" ", "");
	verse = verse.toLowerCase();
	let url = verse + '.txt';
    let request = new XMLHttpRequest();
    request.open('GET', url);
    //将设置我们期待的响应类型 
    request.responseType = 'text';
    //当onload 事件触发时(当响应已经返回时)这个事件会被运行。发生这种情况时, response 数据将在 XHR 请求对象的响应属性中可用。
    request.onload = function() {
        //poemDisplay ( <pre> 元素 ) 的 textContent 设置为 request.response 属性的值。
  		poemDisplay.textContent = request.response;
	};
    //以上都是 XHR 请求的设置 — 在我们告诉它之前,它不会真正运行,这是通过 send() 完成的。
    request.send();
}

function updateDisplay(verse) {
    //文件名为Verse 1,需要转化为verse1.txt
	verse = verse.replace(" ", "");
	verse = verse.toLowerCase();
	let url = verse + '.txt';
    //等价于
    fetch(url).then(function(response) {
       // response 对象有个 text()方法,获取响应主体中的原始数据 a 并把它转换成纯文本,那是我们想要的格式
  		response.text().then(function(text) {
    	poemDisplay.textContent = text;
  		});
	});
}

function updateDisplay(verse) {
    //文件名为Verse 1,需要转化为verse1.txt
	verse = verse.replace(" ", "");
	verse = verse.toLowerCase();
	let url = verse + '.txt';
    //等价于
   fetch(url).then(function(response) {
  		return response.text()
	}).then(function(text) {
  		poemDisplay.textContent = text;
	});
}

客户端api

客户端 JavaScript 中有很多可用的 API — 他们本身并不是 JavaScript 语言的一部分,却建立在 JavaScript 语言核心的顶部,为使用 JavaScript 代码提供额外的超强能力。他们通常分为两类:

  • 浏览器 API内置于 Web 浏览器中,能从浏览器和电脑周边环境中提取数据,并用来做有用的复杂的事情。例如Geolocation API提供了一些简单的 JavaScript 结构以获得位置数据,因此您可以在 Google 地图上标示您的位置。在后台,浏览器确实使用一些复杂的低级代码(例如 C++)与设备的 GPS 硬件(或可以决定位置数据的任何设施)通信来获取位置数据并把 这些数据返回给您的代码中使用浏览器环境;但是,这种复杂性通过 API 抽象出来,因而与您无关。
  • 第三方 API缺省情况下不会内置于浏览器中,通常必须在 Web 中的某个地方获取代码和信息。例如Twitter API 使您能做一些显示最新推文这样的事情,它提供一系列特殊的结构,可以用来请求 Twitter 服务并返回特殊的信息。

浏览器API

操作文档API

操作文档的 API内置于浏览器中。最明显的例子是DOM(文档对象模型)API,它允许您操作 HTML 和 CSS — 创建、移除以及修改 HTML,动态地将新样式应用到您的页面,等等。每当您看到一个弹出窗口出现在一个页面上,或者显示一些新的内容时,这都是 DOM 的行为。 您可以在在Manipulating documents中找到关于这些类型的 API 的更多信息。

服务器端api

从服务器获取数据的 API 用于更新网页的一小部分是相当好用的。这个看似很小的细节能对网站的性能和行为产生巨大的影响 — 如果您只是更新一个股票列表或者一些可用的新故事而不需要从服务器重新加载整个页面将使网站或应用程序感觉更加敏感和“活泼”。使这成为可能的 API 包括XMLHttpRequestFetch API。您也可能会遇到描述这种技术的术语Ajax。您可以在Fetching data from the server找到关于类似的 API 的更多信息。

绘画API

用于绘制和操作图形的 API目前已被浏览器广泛支持 — 最流行的是允许您以编程方式更新包含在 HTML `` 元素中的像素数据以创建 2D 和 3D 场景的CanvasWebGL。例如,您可以绘制矩形或圆形等形状,将图像导入到画布上,然后使用 Canvas API 对其应用滤镜(如棕褐色滤镜或灰度滤镜),或使用 WebGL 创建具有光照和纹理的复杂 3D 场景。这些 API 经常与用于创建动画循环的 API(例如window.requestAnimationFrame())和其他 API 一起不断更新诸如动画和游戏之类的场景。

音频视频api

音频和视频 API例如HTMLMediaElementWeb Audio APIWebRTC允许您使用多媒体来做一些非常有趣的事情,比如创建用于播放音频和视频的自定义 UI 控件,显示字幕字幕和您的视频,从网络摄像机抓取视频,通过画布操纵(见上),或在网络会议中显示在别人的电脑上,或者添加效果到音轨(如增益,失真,平移等) 。

硬件api

设备 API基本上是以对网络应用程序有用的方式操作和检索现代设备硬件中的数据的 API。我们已经讨论过访问设备位置数据的地理定位 API,因此您可以在地图上标注您的位置。其他示例还包括通过系统通知(参见Notifications API)或振动硬件(参见Vibration API)告诉用户 Web 应用程序有用的更新可用。

客户端存储api
  • 客户端存储 API在 Web 浏览器中的使用变得越来越普遍 - 如果您想创建一个应用程序来保存页面加载之间的状态,甚至让设备在处于脱机状态时可用,那么在客户端存储数据将会是非常有用的。例如使用Web Storage API的简单的键 - 值存储以及使用IndexedDB API的更复杂的表格数据存储。

例子

第三方api

API 使用一个或多个 JavaScript objects 在您的代码中进行交互,这些对象用作 API 使用的数据(包含在对象属性中)的容器以及 API 提供的功能(包含在对象方法中)。

让我们回到 Geolocation API 的例子 - 这是一个非常简单的 API,由几个简单的对象组成:

  • Geolocation, 其中包含三种控制地理数据检索的方法
  • Position, 表示在给定的时间的相关设备的位置。 — 它包含一个当前位置的 Coordinates 对象。还包含了一个时间戳,这个时间戳表示获取到位置的时间。
  • Coordinates, 其中包含有关设备位置的大量有用数据,包括经纬度,高度,运动速度和运动方向等。
//在最上方得先引入
<script type="text/javascript" src="https://maps.google.com/maps/api/js?key=AIzaSyDDuGt0E5IEGkcE6ZfrKfUtE9Ko_de66pA"></script>
//我们首先要使用 Geolocation.getCurrentPosition() 方法返回设备的当前位置。浏览器的 Geolocation 对象通过调用 Navigator.geolocation 属性来访问。
//Geolocation.getCurrentPosition() 方法只有一个必须的参数,这个参数是一个匿名函数,当设备的当前位置被成功取到时,这个函数会运行。 这个函数本身有一个参数,它包含一个表示当前位置数据的 Position 对象。
navigator.geolocation.getCurrentPosition(
   //回调函数function,只有getCurrentPosition获得了位置信息position,才会进入
    function(position) {
  var latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
  var myOptions = {
    zoom: 8,
    center: latlng,
    mapTypeId: google.maps.MapTypeId.TERRAIN,
    disableDefaultUI: true
  }
  //通过调用google.maps.Map()构造函数创建一个对象实例来表示我们的地图
  var map = new google.maps.Map(document.querySelector("#map_canvas"), myOptions);
});

补充知识:回调函数

var position = navigator.geolocation.getCurrentPosition();
var myLatitude = position.coords.latitude;

如果第一行还没有返回结果,则第二行将会出现错误,因为位置数据还不可用。出于这个原因,涉及同步操作的 API 被设计为使用 callback functions“回调函数”,

视频和音频、
<video controls>
  <source src="rabbit320.mp4" type="video/mp4">
  <source src="rabbit320.webm" type="video/webm">
  <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p>
</video>

controls属性,它会启用默认的播放设置。如果没有指定该属性,则播放器中不会显示相关控件

作为 HTML5 规范的一部分,HTMLMediaElement API 提供允许你以编程方式来控制视频和音频播放的功能—例如 HTMLMediaElement.play(), HTMLMediaElement.pause(),等。该接口对video和audio两个元素都是可用的,因为在这两个元素中要实现的功能几乎是相同的。让我们通过一个例子来一步步演示一些功能

<!-- 
我们有四个 <button> — play/pause, stop, rewind, and fast forward.
每个<button> 都有一个class名 , 一个data-icon 属性来决定在每个按钮上显示什么图标 (在下一节讲述它是如何工作的), 和一个aria-label 属性为每一个按钮提供容易理解的描述,即使我们没有在 tags 内提供可读的标签。当用户关注这些元素时含有aria-label 属性的内容也会被讲述人读出来。
有一个设定的计时器 <div>用来报告已经播放的时长。为了好玩,我们提供了两种报告机制 — 一个 <span> 包含了流逝时间的分钟和秒,和一个额外的<div> 用来创建一个水平的随着时间增加而增长的进度条
-->
<div class="player">
  <video controls>
    <source src="video/sintel-short.mp4" type="video/mp4">
    <source src="video/sintel-short.mp4" type="video/webm">
    <!-- fallback content here -->
  </video>
  <div class="controls">
    <button class="play" data-icon="P" aria-label="play pause toggle"></button>
    <button class="stop" data-icon="S" aria-label="stop"></button>
    <div class="timer">
      <div></div>
      <span aria-label="timer">00:00</span>
    </div>
    <button class="rwd" data-icon="B" aria-label="rewind"></button>
    <button class="fwd" data-icon="F" aria-label="fast forward"></button>
  </div>
</div>

css就不放了,点击链接

var media = document.querySelector('video');
var controls = document.querySelector('.controls');

var play = document.querySelector('.play');
var stop = document.querySelector('.stop');
var rwd = document.querySelector('.rwd');
var fwd = document.querySelector('.fwd');

var timerWrapper = document.querySelector('.timer');
var timer = document.querySelector('.timer span');
var timerBar = document.querySelector('.timer div');
//删除默认浏览器控件
media.removeAttribute('controls');
controls.style.visibility = 'visible';

play.addEventListener('click', playPauseMedia);
function playPauseMedia() {
     rwd.classList.remove('active');
  fwd.classList.remove('active');
  clearInterval(intervalRwd);
  clearInterval(intervalFwd);
    //如果视频已暂停,HTMLMediaElement.paused 属性将返回 true,任何视频没有播放的时间,包括第一次加载	时处于 0 的时间段都是视频暂停状态。如果已暂停,我们把 play 按钮的 data-icon 属性值设置成"u", 用以表示 "暂停" 按钮图标,并且调用HTMLMediaElement.play() 函数播放视频。
  if(media.paused) {
    play.setAttribute('data-icon','u');
    media.play();
  } else {
    play.setAttribute('data-icon','P');
    media.pause();
  }
}
//click (en-US) 事件很明显——我们想要在点击停止按钮的时候停止视频通过运行我们的 stopMedia() 函数。然而我们也希望停止视频当视频播放完成时——由ended (en-US) 事件标记,
stop.addEventListener('click', stopMedia);
media.addEventListener('ended', stopMedia);

function stopMedia() {
    rwd.classList.remove('active');
  fwd.classList.remove('active');
  clearInterval(intervalRwd);
  clearInterval(intervalFwd);
  media.pause();
  media.currentTime = 0;
  play.setAttribute('data-icon','P');
  
}

//快退快进
rwd.addEventListener('click', mediaBackward);
fwd.addEventListener('click', mediaForward);
var intervalFwd;
var intervalRwd;

function mediaBackward() {
   //要停止 setInterval() 运行,你必须调用 clearInterval()
  clearInterval(intervalFwd);
  //classList是一个非常方便的属性,存在于每个元素上 ––它包含元素上设置的所有类的列表,以及添加/删除类的方法等。使用classList.contains()方法检查列表是否包含active类。这将返回布尔值true/false结果。
  fwd.classList.remove('active');

  if(rwd.classList.contains('active')) {
    rwd.classList.remove('active');
    clearInterval(intervalRwd);
    media.play();
  } else {
    rwd.classList.add('active');
    media.pause();
      //setInterval()会创建一个活动间隔,这意味着它每隔 x 毫秒运行一个作为第一个参数给出的函数,其中 x 是第二个参数的值。所以这里我们每 200 毫秒运行一次windBackward()函数
    intervalRwd = setInterval(windBackward, 200);
  }
}

function mediaForward() {
  clearInterval(intervalRwd);
  rwd.classList.remove('active');

  if(fwd.classList.contains('active')) {
    fwd.classList.remove('active');
    clearInterval(intervalFwd);
    media.play();
  } else {
    fwd.classList.add('active');
    media.pause();
    intervalFwd = setInterval(windForward, 200);
  }
}
function windBackward() {
  if(media.currentTime <= 3) {
    rwd.classList.remove('active');
    clearInterval(intervalRwd);
    stopMedia();
  } else {
    media.currentTime -= 3;
  }
}

function windForward() {
  if(media.currentTime >= media.duration - 3) {
    fwd.classList.remove('active');
    clearInterval(intervalFwd);
    stopMedia();
  } else {
    media.currentTime += 3;
  }
}
//更新已用时间
//以便每次在<video>元素上触发 timeupdate (en-US)事件时更新时间显示。此事件触发的频率取决于您的浏览器,CPU 电源等
media.addEventListener('timeupdate', setTime);
function setTime() {
  var minutes = Math.floor(media.currentTime / 60);
  var seconds = Math.floor(media.currentTime - minutes * 60);
  var minuteValue;
  var secondValue;

  if (minutes < 10) {
    minuteValue = '0' + minutes;
  } else {
    minuteValue = minutes;
  }

  if (seconds < 10) {
    secondValue = '0' + seconds;
  } else {
    secondValue = seconds;
  }

  var mediaTime = minuteValue + ':' + secondValue;
  timer.textContent = mediaTime;
  //通过首先计算外部<div>的宽度来计算出来的(任何元素的clientWidth 属性将包含它的长度),然后乘以HTMLMediaElement.currentTime除以媒体的总HTMLMediaElement.duration。
  var barLength = timerWrapper.clientWidth * (media.currentTime/media.duration);
  timerBar.style.width = barLength + 'px';
}

操作文档

在编写 web 页面或应用时,你最想做的事情之一就是以某种方式操作文档结构。这通常使用一套大量使用Document对象来控制 HTML 和样式信息的文档对象模型(DOM)来实现

在这里插入图片描述

  • window 是载入浏览器的标签,在 JavaScript 中用Window对象来表示,使用这个对象的可用方法,你可以返回窗口的大小(参见Window.innerWidthWindow.innerHeight),操作载入窗口的文档,存储客户端上文档的特殊数据(例如使用本地数据库或其他存储设备),为当前窗口绑定event handler,等等。v
  • navigator 表示浏览器存在于 web 上的状态和标识(即用户代理)。在 JavaScript 中,用Navigator来表示。你可以用这个对象获取一些信息,比如来自用户摄像头的地理信息、用户偏爱的语言、多媒体流等等
  • document(在浏览器中用 DOM 表示)是载入窗口的实际页面,在 JavaScript 中用Document 对象表示,你可以用这个对象来返回和操作文档中 HTML 和 CSS 上的信息。例如获取 DOM 中一个元素的引用,修改其文本内容,并应用新的样式,创建新的元素并添加为当前元素的子元素,甚至把他们一起删除
基本的DOM操作
获取改变节点
//获取a元素 存储在变量引用
var link = document.querySelector('a');
//更新链接的文字
link.textContent = 'Mozilla Developer Network';
//更新链接的url
link.href = 'https://developer.mozilla.org';
/**
注意,和 JavaScript 中的许多事情一样,有很多方法可以选择一个元素,并在一个变量中存储一个引用。Document.querySelector()是推荐的主流方法,它允许你使用 CSS 选择器选择元素,使用很方便。上面的querySelector()调用会匹配它在文档中遇到的第一个<a>元素。如果想对多个元素进行匹配和操作,你可以使用Document.querySelectorAll(),这个方法匹配文档中每个匹配选择器的元素,并把它们的引用存储在一个array中。
*/



创建放置节点
var sect = document.querySelector('section');
var para = document.createElement('p');
para.textContent = 'We hope you enjoyed the ride.';
sect.appendChild(para);
var text = document.createTextNode(' — the premier source for web development knowledge.');
var linkPara = document.querySelector('p');
linkPara.appendChild(text);
移动删除节点
//这样可以把段落下移到 section 的底部。你可能想过要做第二个副本,但是情况并非如此 — linkPara是指向该段落唯一副本的引用。如果你想做一个副本并也把它添加进去,只能用Node.cloneNode() 方法来替代。
sect.appendChild(linkPara);
//删除-你拥有要删除的节点和其父节点的引用
sect.removeChild(linkPara);
//要删除一个仅基于自身引用的节点可能稍微有点复杂
linkPara.parentNode.removeChild(linkPara);

操作样式
para.setAttribute('class', 'highlight');
Window对象
var div = document.querySelector('div');
//每次窗口调整大小时都会触发该事件:将div改变为窗口的大小
window.onresize = function() {
  WIDTH = window.innerWidth;
  HEIGHT = window.innerHeight;
  div.style.width = WIDTH + 'px';
  div.style.height = HEIGHT + 'px';
}

参考链接:https://developer.mozilla.org/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值