黑白之海
当指针转向天台

前端 | JavaScript基础

在?看看代码。

js内容多,单独开篇。


参考网络教程为MDN Web Docs

很多人认为,与相关技术如 HTML 和 CSS 相比,学习 JavaScript 更为困难。

练习网站我用的Glitch


JavaScript

  • JavaScript 第一步 3h40min
  • 编写 JavaScript / JavaScript基础要件 4h
  • JavaScript 对象入门 6.5h
  • 异步 JavaScript 2h15min
  • 客户端 Web API 4h15min

Web 表单 — 处理用户数据

  • Web 表单

可访问性——让所有人都能使用 Web

  • 跨浏览器测试
  • 可访问性(辅助功能)

现代工具

  • Git 和 GitHub
  • 客户端 Web 开发工具入门
  • 客户端 JavaScript 开发框架入门 (React / Ember / Vue )

服务端网页编程

  • 第一步
  • Django网站框架(python)
  • Express网页框架(node.js / JavaScript)

JavaScript第一步

变量

一个可靠的命名约定叫做 “小写驼峰命名法”,用来将多个单词组在一起,小写整个命名的第一个字母然后大写剩下单词的首字符。我们已经在文章中使用了这种命名方法。

字符串替换

replace只会替换找到的第一个,所以有重复的部分需要替换多次。

JavaScript基础要件

条件

三元运算符

感觉不太用到,我都没什么印象……?

循环

唔这个大家都会,略【 话说我不知道为什么课后练习我用replace替换最后一位逗号不行啊?我没想通嘤嘤嘤!!

函数与方法

math.random

Math.floor(Math.random()*number) // 0到number的随机整数,左闭右开
Math.floor(Math.random()*(number+1)) // 0到number的随机整数,闭区间

Math.floor(Math.random() * (max - min)) + min // min到max的随机整数,左闭右开
Math.floor(Math.random() * (max - min + 1)) + min //min到max的随机整数,闭区间

事件

事件捕获

事件冒泡

stopPropagation()打断冒泡。

JavaScript对象介绍

点表示法

括号表示法

OOP

Object-oriented programming (OOP)

类和构造函数

原型

字符串拼接

'常量'+a+'常量' 等价于 '常量连接变量${a}与常量'

彩球弹射

发现中文英文的代码居然写得不一样……

点击展开:中文版
const canvas = document.querySelector("canvas");

const ctx = canvas.getContext("2d");

const width = (canvas.width = window.innerWidth);
const height = (canvas.height = window.innerHeight);

function random(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
} // 这段我总觉得中文版的开闭区间有问题所以抄的英文版

function randomRGB() {
  return `rgb(${random(0, 255)},${random(0, 255)},${random(0, 255)})`;
}

function Ball(x, y, velX, velY, color, size) {
  this.x = x;
  this.y = y;
  this.velX = velX;
  this.velY = velY;
  this.color = color;
  this.size = size;
}

Ball.prototype.draw = function () {
  ctx.beginPath();
  ctx.fillStyle = this.color;
  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI); // 0是角度,2 * Math.PI是360°完整的圆
  ctx.fill();
};

Ball.prototype.update = function() { //圆形不出框外
  if ((this.x + this.size) >= width) {
    this.velX = -(this.velX);
  }

  if ((this.x - this.size) <= 0) {
    this.velX = -(this.velX);
  }

  if ((this.y + this.size) >= height) {
    this.velY = -(this.velY);
  }

  if ((this.y - this.size) <= 0) {
    this.velY = -(this.velY);
  }

  this.x += this.velX;
  this.y += this.velY;
}
Ball.prototype.collisionDetect = function() { // 碰撞检测
  for (let j = 0; j < balls.length; j++) {
    if (this !== balls[j]) { // 不是这个圆本身
      const dx = this.x - balls[j].x;
      const dy = this.y - balls[j].y;
      const distance = Math.sqrt(dx * dx + dy * dy); // 也就是两点之间用勾股定理求直线距离

      if (distance < this.size + balls[j].size) { // 如果两个小球中心的距离小于两个小球的半径之和,判定为相撞,则改变颜色
        balls[j].color = this.color = randomRGB();
      }
    }
  }
}

let balls = [];

while (balls.length < 25) {
    let size = random(10, 20);
    let ball = new Ball(
      // 为避免绘制错误,球至少离画布边缘球本身一倍宽度的距离
      random(0 + size, width - size),
      random(0 + size, height - size),
      random(-7, 7),
      random(-7, 7),
      randomRGB(),
      size
    );
    balls.push(ball);
  }
function loop() { // 运动循环,也就是每一帧都自动更新视图。这是大多数游戏或者其他类似项目的基础。
  ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
  ctx.fillRect(0, 0, width, height);

  for (let i = 0; i < balls.length; i++) {
    balls[i].draw();
    balls[i].update();
    balls[i].collisionDetect();

  }

  requestAnimationFrame(loop); // 使用 requestAnimationFrame() 方法再运行一次函数 —— 当一个函数正在运行时传递相同的函数名,从而每隔一小段时间都会运行一次这个函数,这样我们可以得到一个平滑的动画效果。这主要是通过递归完成的 —— 也就是说函数每次运行的时候都会调用自己,从而可以一遍又一遍得运行。
}

loop();

 

点击展开:英文版
const canvas = document.querySelector("canvas");

const ctx = canvas.getContext("2d");

const width = (canvas.width = window.innerWidth);
const height = (canvas.height = window.innerHeight);

function random(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function randomRGB() {
  return `rgb(${random(0, 255)},${random(0, 255)},${random(0, 255)})`;
}
class Ball {
  constructor(x, y, velX, velY, color, size) {
    this.x = x;
    this.y = y;
    this.velX = velX;
    this.velY = velY;
    this.color = color;
    this.size = size;
  }
  draw() {
  ctx.beginPath();
  ctx.fillStyle = this.color;
  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
  ctx.fill();
}
  update() {
  if ((this.x + this.size) >= width) {
    this.velX = -(this.velX);
  }

  if ((this.x - this.size) <= 0) {
    this.velX = -(this.velX);
  }

  if ((this.y + this.size) >= height) {
    this.velY = -(this.velY);
  }

  if ((this.y - this.size) <= 0) {
    this.velY = -(this.velY);
  }

  this.x += this.velX;
  this.y += this.velY;
}
collisionDetect() {
  for (const ball of balls) {
    if (this !== ball) {
      const dx = this.x - ball.x;
      const dy = this.y - ball.y;
      const distance = Math.sqrt(dx * dx + dy * dy);

      if (distance < this.size + ball.size) {
        ball.color = this.color = randomRGB();
      }
    }
  }
}

  
}

const balls = [];

while (balls.length < 25) {
  const size = random(10,20);
  const ball = new Ball(
    // ball position always drawn at least one ball width
    // away from the edge of the canvas, to avoid drawing errors
    random(0 + size, width - size),
    random(0 + size, height - size),
    random(-7, 7),
    random(-7, 7),
    randomRGB(),
    size
  );

  balls.push(ball);
}

function loop() {
  ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
  ctx.fillRect(0, 0, width, height);

  for (const ball of balls) {
    ball.draw();
    ball.update();
    ball.collisionDetect();
  }

  requestAnimationFrame(loop);
}
loop();

点击展开:添加恶魔圈的弹球
const para = document.querySelector('p'); // 添加一个对应html中段落的常量
let count = 0; // 声明一个计数的变量

const canvas = document.querySelector("canvas");

const ctx = canvas.getContext("2d");

const width = (canvas.width = window.innerWidth);
const height = (canvas.height = window.innerHeight);

function random(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
} 

function randomRGB() {
  return `rgb(${random(0, 255)},${random(0, 255)},${random(0, 255)})`;
}

class Shape {
  constructor(x, y, velX, velY) { // 讲道理这个构造我还是不太明白什么时候写多少【【
    this.x = x;
    this.y = y;
    this.velX = velX;
    this.velY = velY;
  }
}
class Ball extends Shape {
  constructor(x, y, velX, velY, color, size) { // 比如这里为什么不用写exists啊?
    super(x, y, velX, velY);
    this.color = color;
    this.size = size;
    this.exists = true;
  }
}

Ball.prototype.draw = function () {
  ctx.beginPath();
  ctx.fillStyle = this.color;
  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI); // 0是角度,2 * Math.PI是360°完整的圆
  ctx.fill();
};

Ball.prototype.update = function () {
  //圆形不出框外
  if (this.x + this.size >= width) {
    this.velX = -this.velX;
  }

  if (this.x - this.size <= 0) {
    this.velX = -this.velX;
  }

  if (this.y + this.size >= height) {
    this.velY = -this.velY;
  }

  if (this.y - this.size <= 0) {
    this.velY = -this.velY;
  }

  this.x += this.velX;
  this.y += this.velY;
};
Ball.prototype.collisionDetect = function () {
     for (const ball of balls) {
        if (!(this === ball) && ball.exists) {
           const dx = this.x - ball.x;
           const dy = this.y - ball.y;
           const distance = Math.sqrt(dx * dx + dy * dy);

           if (distance < this.size + ball.size) {
             ball.color = this.color = randomRGB();
           }
        }
     }
};

class EvilCircle extends Shape {
  constructor(x, y) { // 又比如这里为什么只需要写xy啊?
    super(x, y, 20,20);
    this.color = "white";
    this.size = 10;
  }
}

EvilCircle.prototype.draw = function () {
  ctx.beginPath();
  ctx.lineWidth = 3;
  ctx.strokeStyle = this.color;
  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI); // 0是角度,2 * Math.PI是360°完整的圆
  ctx.stroke();
};

EvilCircle.prototype.checkBounds = function () {
  //圆形不出框外,这段倒是自己理解能写出来……就是更简略的写法也有,加减号放前面加一个等号
  if (this.x + this.size >= width) {
    this.x = this.x - this.size;
  }

  if (this.x - this.size <= 0) {
    this.x = this.x + this.size;
  }

  if (this.y + this.size >= height) {
    this.y = this.y - this.size;
  }

  if (this.y - this.size <= 0) {
    this.y = this.y + this.size;
  }
};

EvilCircle.prototype.setControls = function () {
  window.onkeydown = (e) => {
    switch (e.key) {
      case "a":
        this.x -= this.velX;
        break;
      case "d":
        this.x += this.velX;
        break;
      case "w":
        this.y -= this.velY;
        break;
      case "s":
        this.y += this.velY;
        break;
    }
  };
};

EvilCircle.prototype.collisionDetect = function () {
  // 碰撞检测
    for (const ball of balls) { // 这个条件语句注意
      if (ball.exists) {
        const dx = this.x - ball.x;
        const dy = this.y - ball.y;
        const distance = Math.sqrt(dx * dx + dy * dy);

        if (distance < this.size + ball.size) {
          ball.exists = false; // 判断相撞则将该ball的exists属性改为假
          count--; // 并且计数自减
          para.textContent = 'Ball count: ' + count; // 计数有变动就传值
        }
      }
    }
};
const balls = [];

while (balls.length < 25) {
  const size = random(10, 20);
  const ball = new Ball(
    // ball position always drawn at least one ball width
    // away from the edge of the canvas, to avoid drawing errors
    random(0 + size, width - size),
    random(0 + size, height - size),
    random(-7, 7),
    random(-7, 7),
    randomRGB(),
    size
  );
  balls.push(ball);
  count++; // 每次循环计数自增
  para.textContent = 'Ball count: ' + count; // 传值到html的段落中
}

const evilBall = new EvilCircle(random(0, width), random(0, height)); // 因为构造里只有xy所以这里也只需要两个参数

function loop() {
  ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
  ctx.fillRect(0, 0, width, height);

  for (const ball of balls) {
    if (ball.exists) { // 若ball的exists属性为真,才绘制ball,也就解释了为什么恶魔圈碰撞检测为真,并设置相撞的ball的exists属性为假的时候,ball会“消失”
      ball.draw();
      ball.update();
      ball.collisionDetect();
    }
  }

  evilBall.draw();
  evilBall.checkBounds();
  evilBall.collisionDetect();

  requestAnimationFrame(loop);
}

loop();


异步JavaScript

可以说我完全没懂吗,我自己都不知道怎么跑通了()

客户端API

这个参考答案里为什么要用异步啊我懵!!

点击展开:操作文档

const list = document.querySelector('ul');
const input = document.querySelector('input');
const button = document.querySelector('button');


function Add(){ //定义新增的要放这里面,不然只会存在一个,反复在原来的那个上修改
  let cust=  input.value; // 注意这里是value,我之前一直以为也是textContent(瀑布汗)
  let li = document.createElement("li");
  let del = document.createElement("button");
  del.textContent = 'Delete';
  let span= document.createElement("span");
  li.appendChild(span);
  li.appendChild(del);
  list.appendChild(li);
  span.textContent= cust;
  input.value = '';
  function Del(){
  list.removeChild(li)
}
  del.addEventListener('click', Del);
  input.focus();
}
button.addEventListener('click', Add);