进度:React
课程链接 > 课程资料 > 体验拉满的课程,非常值得学习。虽然是一个 crash course,但内容非常丰富。并且最重要的是实验课每一步都有完整的代码引导(通过 git-branch),再也没有因为一步没有跟上或者代码有小 bug 导致整个实验课体验炸裂的情况发生(debug 一节课导致什么都没学到)

Introduction

client
server

Webpage files

  • HTML
  • CSS
  • JS
  • Assets

Git basics

HTML/CSS

HTML: structure - nested boxes
CSS: functionality - a list of descriptions

Opening tag and closing tag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<html>
root of html doc
<head>
doc info
<body>
<h1>
<h2>
<h3>
... Header
<p>paragraph</p>
<div>
generic block section <span> generic inline section </span>
</div>
</h3>
</h2>
</h1>
</body>
</head>
</html>

HTML attribute

1
2
<tagmame abc = "xyz">
</tagname>

<a herf = "link">

Inserting images

<img src = ""/>

Lists

1
2
3
4
5
6
7
<ol>
ordered list
<ul>
unordered list
<li>list item</li>
</ul>
</ol>

sapn & div

div: group things together in a block

just use <div>?
<div> should be used only when no other semantic element

1
2
3
4
5
6
7
8
<section>
<artcle>
<nav>
<header>
<footer></footer>
</header></nav
></artcle>
</section>

Section

  • margin
  • border
  • padding
  • content

8pt Grid System

1
2
3
4
5
6
:root {
  --xs: 4px;
  --s: 8px;
  --m: 16px;
  --l: 24px;
}

Perfect circle picture

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.avatarContainer {
  padding: 0 35%;
}

.avatar {
  /* make it responsive */
  max-width: 100%;
  width: 100%;
  height: auto;
  display: block;
  /* div height to be the same as width*/
  padding-top: 100%;
  /* make it a circle */

  border-radius: 50%;
 
  /* Add image */
  background-image: url("cat.png");
  /* Centering on image`s center*/
  background-position-y: center;
  background-position-x: center;
  background-repeat: no-repeat;
  /* it makes the clue thing, takes smaller dimension to fill div */
  background-size: cover;
  /* it is optional, for making this div centered in parent*/
  margin: 0 auto;
}
1
2
3
4
5
6
 
<div class="avatarContainer">
   
<div class="avatar"></div>
 
</div>

Flex box

a flexible box

  • direction
  • sizing
  • distribution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   
<div class="u-flex">
     
<section class="u-textCenter">
       
<h4>About Me</h4>
       
<p>
          I am more of a turtle person but I'm just trying to fit in and
get a catbook.        
</p>
     
</section>
     
<section class="u-textCenter">
       
<h4>My Favorite Type of Cat</h4>
       
<p>          I actually prefer turtles.        </p>
     
</section>
   
</div>
1
2
3
.u-flex {
  display: flex;
}

CSS: a list of description

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
div {
/*selector*/
color: red;
font-family: Arial;
font-size: 24pt;
/*property and value*/
}

.info {
/*selector: target only elements with class "info"*/
color: red;
font-family: Arial;
font-size: 24pt;
/*property and value*/
}

#unque {
/*selector: target only elements with id "unique"*/
color: red;
font-family: Arial;
font-size: 24pt;
/*property and value*/
}

CSS Hierarchy

inline > ID > class > div

example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* Your Code Here! */
@import url("https://fonts.googleapis.com/css2?family=Playwrite+MX:wght@100..400&display=swap");

body {
  font-family: "Playwrite MX", cursive;
}
/*apply in <body>*/
.u-textCenter {
  text-align: center;
}

:root {
  --primary: rgb(197, 68, 193);
  --gray: gray;
  --white: white;
}
/*variables*/
.navTable {
  color: var(--primary);
  font-size: 50px;
}

JavaScript

Data types

  • Boolean
  • Number
  • String
  • Null
  • Undefined

Operators

Syntax

Define variables
1
2
3
4
5
6
let myBool = true;
let myString = "Hello";

const pi = 3.14;

myBool = false;

let: block-scoped
var: function-scoped

1
2
3
4
5
let firstName;
// undefined
firstName = "Albert";
firstName = null;
//null(empty) !== undefined

output

1
2
3
console.log(firstName);
console.log(`a * b = ${a * b}`);
alert("Congratulations");

arrays

1
2
3
4
5
6
7
8
9
10
11
12
13
let pets = ["flowers", 42, false, "bird"];

console.log(pets[2]);

pets[3] = "dog";
pets.push("dog");
pets.pop(); //remove from end
pets.unshift("cat");

//looping through an array
for (let i = 0; i < pets.length; i++) {
console.log(pets[i]);
}

conditionals & loops

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let z = 1;
while (z < 1000) {}

for (let i = 0; i < pet.length(); i++) {
const phrase = "I love my" + pets[i];
console.log(phrase);
}

for (const animal of pets) {
const phrase = "I love my" + animal;
console.log(phrase);
}

if (z > 2) {
} else if (z < 0) {
} else {
}

Object

a collection of name:value pairs

1
2
3
4
5
6
7
8
9
const myCar = {
make: "Ford",
model: "Mustang",
year: "2005",
color: "red",
};

console.log(myCar.model);
console.log(myCar[color]);

obtain object properties at once

1
const { make, model } = myCar;

Object variables are references!

copy reference variables

1
2
3
4
5
let arr = [1, 2, 3];
let copyArr = [...arr];

let obj = { name: "Tom" };
let copyObj = { ...obj };

Functions

1
2
3
4
5
const myFunc = (parameters) => {
//body
let tmp = parameters * 2;
return tmp;
};
  • printSomething : the function itself
  • printSomething( ) : the return value
  • (parameter) => { } : a function

Classes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
//constructor
getArea = () => {
return (this.width * this.height) / 2;
};
//methods
}

const rect = new Rectangle(6, 8);
console.log(rect.getArea()); //48

Callback Function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const arrCtoF = (arrC) => {
//
const arrF = [...arrC];
for (let i = 0; i < arrC.length; i++) {
arrF[i] = (arrF[i] * 9) / 5 + 32;
}
return arrF;
};
const arrFtoC = (arrF) => {
//
};

const modifyArray = (arr, transformFunc) => {
const newArr = [];
for (let i = 0; i < arr.length; i++) {
newArr.push(transformFunc(arr[i]));
}
return newArr;
};
//transformFuncs
const CtoF = (tempC) => {
return (tempC * 9) / 5 + 32;
};
const FtoC = (tempF) => {
//
};
//usage
newArr = modifyArray(arr, CtoF);
newArr = modifyArray(arr, (tempC) => (tempC * 9) / 5 + 32);

Map

1
2
3
4
5
6
7
8
9
10
const myArray = [1, 2, 3, 4];
const newArray = myArray.map((num) => num * 3);

const rectangles = [
{ width: 1, height: 2 },
{ width: 5, height: 6 },
{ width: 3, height: 2 },
];

const area = rectangles.map((rectangle) => rectangle.height * rectangle.width);

Filter

1
2
3
let values = [1, -2, 3, -4, 5];
let positiveValues = values.filter((num) => num > 0);
//[1, 3, 5]
**Why do we use callback functions?** when something happens => do something we only need to dictate what to do e.g.
1
2
setInterval(updateAnimate, 10);
//call updateAnimate func every 10ms

Workshop 1 - JS

index.html

index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!DOCTYPE html>
<html lang="en">
 
<head>
   
<link rel="stylesheet" href="style.css" />
   
<meta charset="UTF-8" />
   
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
   
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
   
<title>Snake</title>
   
<script src="snake.js"></script>
   
<script src="input.js"></script>
   
<script src="food.js"></script>
   
<script src="snakeUtils.js"></script>
   
<script src="game.js" defer></script>
 
</head>
 
<body>
   
<div id="game-board"></div>
 
</body>
</html>

game.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const SNAKE_SPEED = 5;

const gameBoard = document.getElementById("game-board");

let isGameOver = false;

const main = () => {
update();
draw();
// TODO 4.3, 4.4: Add Game Over Alert, and clear interval!
if (isGameOver) {
alert("Game Over!");
clearInterval(gameLoop);
}
};

// TODO 4.4: Define the interval ID
// HINT: ONLY EDIT THE LINE BELOW!
let gameLoop = setInterval(main, 1000 / SNAKE_SPEED);

const update = () => {
console.log("Updating");
updateSnake();
updateFood();
// TODO 4.2: Update Game State
isGameOver = checkGameOver();
};

const draw = () => {
gameBoard.innerHTML = "";
drawSnake(gameBoard);
drawFood(gameBoard);
};

// TODO 4.1: Create a function that checks if the game is over

const checkGameOver = () => {
let ret = false;
if (snakeIntersectSelf() || snakeOutOfBounds()) {
ret = true;
}
return ret;
};

food.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let food = { x: 4, y: 16 };

const updateFood = () => {
if (onSnake(food)) {
growSnake();
food = getNewFoodPosition();
}
};

// Don't change me!
const drawFood = (gameBoard) => {
const foodElement = document.createElement("div");
foodElement.style.gridRowStart = food.y;
foodElement.style.gridColumnStart = food.x;
foodElement.classList.add("food");
gameBoard.appendChild(foodElement);
};

input.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let inputDirection = { x: 0, y: 1 };

window.addEventListener("keydown", (event) => {
if (event.key === "ArrowUp" && inputDirection.x !== 0) {
inputDirection = { x: 0, y: -1 };
} else if (event.key === "ArrowDown" && inputDirection.x !== 0) {
inputDirection = { x: 0, y: 1 };
} else if (event.key === "ArrowRight" && inputDirection.y !== 0) {
inputDirection = { x: 1, y: 0 };
} else if (event.key === "ArrowLeft" && inputDirection.y !== 0) {
inputDirection = { x: -1, y: 0 };
} else if (event.key === "R") {
resetGame();
}
});

const getInputDirection = () => {
return inputDirection;
};

snake.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const snakeBody = [
{ x: 11, y: 11 },
{ x: 11, y: 10 },
{ x: 11, y: 9 },
];

const updateSnake = () => {
// Remove tail segment
snakeBody.pop();

// Add new head segment
const newHead = { ...snakeBody[0] };
const snakeDirection = getInputDirection();

newHead.x += snakeDirection.x;
newHead.y += snakeDirection.y;

snakeBody.unshift(newHead);
};

// Don't change this function!
const drawSnake = (gameBoard) => {
for (let i = 0; i < snakeBody.length; i++) {
const segment = snakeBody[i];
const snakeElement = document.createElement("div");
snakeElement.style.gridRowStart = segment.y;
snakeElement.style.gridColumnStart = segment.x;
snakeElement.classList.add("snake");
gameBoard.appendChild(snakeElement);
}
};

snakeUtils.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
const GRID_SIZE = 21;

const onSnake = (position) => {
for (let i = 0; i < snakeBody.length; i++) {
if (equalPositions(position, snakeBody[i])) {
return true;
}
}
return false;
};

const equalPositions = (pos1, pos2) => {
return pos1.x === pos2.x && pos1.y === pos2.y;
};

const growSnake = () => {
snakeBody.push({ ...snakeBody[snakeBody.length - 1] });
};

const getNewFoodPosition = () => {
let randomFoodPosition = randomGridPosition();
while (onSnake(randomFoodPosition)) {
randomFoodPosition = randomGridPosition();
}
return randomFoodPosition;
};

const randomGridPosition = () => {
return {
x: Math.floor(Math.random() * GRID_SIZE) + 1,
y: Math.floor(Math.random() * GRID_SIZE) + 1,
};
};

const outOfBounds = (position) => {
return (
position.x < 1 ||
position.x > GRID_SIZE ||
position.y < 1 ||
position.y > GRID_SIZE
);
};

const snakeOutOfBounds = () => {
return outOfBounds(snakeBody[0]);
};

const snakeIntersectSelf = () => {
for (let i = 1; i < snakeBody.length; i++) {
if (equalPositions(snakeBody[0], snakeBody[i])) {
return true;
}
}
return false;
};

style.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/* No need to edit this file! */

body {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
background-color: gray;
}

#game-board {
background-color: black;
width: 100vmin;
height: 100vmin;
display: grid;
grid-template-rows: repeat(21, 1fr);
grid-template-columns: repeat(21, 1fr);
}

.snake {
background-color: lime;
border: 0.25vmin solid black;
}

.food {
background-color: red;
border: 0.25vmin solid gray;
}

React

A JS library for building user interfaces
fake HTML tags

React Apps are components of components


Props

parent -> child component