Version | Erscheinung | Elemente ca. |
---|---|---|
HTML 1.0 | 1993 | 20 |
HTML 2.0 | 1995 | 50 |
HTML 3.2 | 1997 | 70 |
HTML 4.01 | 1999 | 90 |
HTML 5.0 | 2014 | 110 |
selector [, selector, selector, ...] {
property: value;
}
html {
background-color: red;
font-size: 30px;
}
#my-id /* ID */
html, body /* Mehrfachselektion */
div > p /* p die direkt unterhalb eines div sind */
div p /* p die irgendwo unterhalb eines div sind */
a:visited /* besuchte Links */
div:hover /* divs über die man mit der Maus fährt */
span.important /* span mit der Klasse "important" */
Es gibt zwei grundlegende Blocktypen:
block
inline
Beansprucht eine ganze Zeile und verursacht Zeilenumbrüche
display: block;
Kann Breite und Höhe haben
display: block;
width: 20px;
height: 20px;
Wie einfacher Text, der mit anderen in der gleichen Zeile stehen kann
display: inline;
Festlegen von Breite und Höhe sind wirkungslos
display: inline;
width: 20px; /* kein Effekt */
height: 20px; /* kein Effekt */
Mischform von inline
und block
display: inline-block;
width: 20px;
height: 20px;
Regeln können andere Regeln überschreiben
#id:hover { display: none }
#id { display: block }
.class.clazz { display: inline }
div { display: inline-block }
Es gibt zwei Varianten des Modells:
content-box
(default)
border-box
box-sizing: content-box;
box-sizing: border-box;
div {
border: 3px solid red;
padding: 10px;
width: 100px;
}
.border-box {
box-sizing: border-box;
}
.content-box {
box-sizing: content-box;
}
/* default, da wo es in der Seite steht */
position: static;
/* relativ zu seiner eigentlichen Position */
position: relative;
/* relativ zu seinem nächsten non-static parent o. window */
position: absolute;
position: relative;
position: absolute;
erlauben Verschiebung mittels
top: 10px;
left: 10px;
right: 10px;
bottom: 10px;
.menu-item {
display: inline-block;
position: relative;
}
.menu-item .children {
display: none;
position: absolute;
}
.menu-item:hover .children {
display: block;
}
Version | ECMA Standard | Jahr |
---|---|---|
ES1 | ECMAScript 1 | 1997 |
ES2 | ECMAScript 2 | 1998 |
ES3 | ECMAScript 3 | 1999 |
ES5 | ECMAScript 5 | 2009 |
ES6 | ECMAScript 2015 | 2015 |
... | ||
ECMAScript 2020 | 2020 |
Code wird zwischen script
-Tags geschrieben
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
</head>
<body>
<script>// code</script>
</body>
</html>
DOM-API
// findet das erste Element
const parent = document.querySelector("#id");
// findet alle Elemente
const elements = document.querySelectorAll("#id");
// Element erstellen
const newElement = document.createElement("div");
newElement.addEventListener("click", (event) => {
// Click-Event
});
// Element anhängen
parent.appendChild(newElement);
newElement.remove();
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script src="index.js"></script>
</body>
</html>
Parsen eines HTML-Dokuments
Verschiedene Varianten, JavaScript erst am Ende auszuführen
Damals mit jQuery:
<!DOCTYPE html>
<html>
<head>
<script>
$(document).ready((event) => {
const element = document.querySelector("#hello");
});
</script>
</head>
<body>
Hello World!
</body>
</html>
script
-Tag am Ende
<!DOCTYPE html>
<html>
<head>
</head>
<body>
Hello World!
...
<script src="index.js"></script>
</body>
</html>
Event-basiert, z.B. per DOMContentLoaded
<!DOCTYPE html>
<html>
<head>
<script>
document.addEventListener("DOMContentLoaded", (event) => {
// wird ausgeführt, sobald das Dokument geparst wurde
const element = document.querySelector("#hello");
});
</script>
</head>
<body>
Hello World!
</body>
</html>
Moderne Variante
<script src="index.js" defer></script>
document
-Operationen
document.open();
document.write("Booo!");
document.close();
<body>
<script>document.write("Dies ist ein Text.
")</script>
<script>
const button = document.querySelector("button");
button.addEventListener("click", () => {
document.write("Und pfutsch!");
});
</script>
</body>
Version | Jahr |
---|---|
0.9 | 1991 |
1.0 | 1996 |
1.1 | 1999 |
2.0 | 2015 |
3.0 | 2022 |
Request an www.google.de
GET / HTTP/1.1
Host: www.google.de
User-Agent: curl/7.88.1
Accept: */*
Response von www.google.de
HTTP/1.1 200 OK
Date: Tue, 04 Apr 2023 15:45:26 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
Content-Security-Policy-Report-Only: [...]
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: [...]
Accept-Ranges: none
Vary: Accept-Encoding
Transfer-Encoding: chunked
<!doctype html><html>...</html>
Einfach mal testen:
curl -v --http1.0 http://www.google.de
curl -v --http1.1 http://www.google.de
curl -v --http2 http://www.google.de
curl -v --http2-prior-knowledge http://www.google.de
curl -v --http3 http://www.google.de
Verschiedene "Verben" bzw. "Methoden"
Beispiel:
git clone https://git.furnco.de/r/public/web-development/examples.git
cd examples/templates/005-http-rest
node index.js
curl -X GET -is http://localhost:3000/todo
curl -X POST -H "Content-Type: application/json" -d '{"name": "Einkaufen"}' -is http://localhost:3000/todo
curl -X POST -H "Content-Type: application/json" -d '{"name": "Putzen"}' -is http://localhost:3000/todo
curl -X PUT -H "Content-Type: application/json" -d '{"name": "Schlafen"}' -is http://localhost:3000/todo/1
curl -X DELETE -is http://localhost:3000/todo/0
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 13
ETag: W/"d-KMmUcQ1kigqtwzZnU+jVDkYP3Co"
Date: Wed, 05 Apr 2023 12:05:05 GMT
Connection: keep-alive
Keep-Alive: timeout=5
["Einkaufen"]
app.get("/todo", (req, res) => {
return res.json(todos);
});
// [...]
app.post("/todo", (req, res) => {
// [...]
return res.json(todos);
// [...]
});
GET
und POST
auf klassischen Webseiten
Beispiel:
cd examples/templates/006-http-web
node index.js
"
) gesetzt werdenDefinition eines einfachen Objekts in JS
const o = {
x: 1,
y: 2
};
Entsprechung in JSON
{
"x": 1,
"y": 2
}
Mögliche Typen
Der äußere Container kann ein Array oder ein Object sein
{
"key": "value",
}
[
"foo",
"bar"
]
c / c++ | Java | C# | JS | |
---|---|---|---|---|
Formale Spezifikation | ja | |||
Übersetzung | Nativ kompiliert | Bytecode | Interpretiert / kompiliert (JIT) | |
Typisierung | statisch | dynamisch | ||
Speicher-Management | Manuell | Garbage Collector |
function add(x, y) {
return x + y;
}
const a = 5;
const b = add(a, 6);
const c = [];
# im Ordner 'examples/'
. hooks/post-checkout
# node [Script-Datei], z.B.
node index.js
console.log("Hello World!");
// < es6
var x = 1;
// >= es6
let y = 2;
const z = 3;
var yes = false;
if (yes) {
var a = 1;
}
console.log(a);
undefined
var yes = false;
if (yes) {
let a = 1;
}
console.log(a);
ReferenceError: a is not defined
function foo() {
var yes = false;
if (yes) {
var a = 1;
}
}
foo();
console.log(a);
ReferenceError: a is not defined
var
function
-Scope
var yes = false;
var a;
if (yes) {
a = 1;
}
console.log(a);
let
, const
let x = 5; // Number (Integer)
let f = 1.25; // Number (Float)
let b = true; // Boolean
let s = "hallo"; // String
let a = []; // Array
let o = {}; // Objekt
let nan = NaN; // Not a Number
let n = null; // Null
let u = undefined; // Undefiniert
if (x == 1) {
// Code
}
else if (x == 2) {
// alternativer Code
}
else {
// Fallback
}
for (let i = 0; i < 5; i++) {
// Code
}
const a = [1, 2, 3];
for (const element of a) {
// Code
}
while (i == 1) {
// Code
}
do {
// Code
} while (i == 1)
let a = [1, 2, 3];
a.push(4);
a.push(5);
a.pop();
console.log(a);
[1, 2, 3, 4]
let o = {x: 1, y: 2};
console.log(o.z);
console.log(o);
o.z = 3;
console.log(o);
undefined
{ x: 1, y: 2 }
{ x: 1, y: 2, z: 3 }
let o = {};
o.a = 1;
o["a"] = 1; // alternativ
o["$ !"] = 2; // so sind auch komplexe Schlüssel möglich
// o."$ !" = 2; => Syntaxfehler
// o.$ ! = 2; => Syntaxfehler
o[true] = 3;
console.log(Object.keys(o));
[ 'a', '$ !', 'true' ]
function foo() {
console.log("foo");
}
function bar(a) {
return a;
}
foo();
const a = bar(1);
console.log(a);
foo
1
let sum = function(a, b) {
return a + b;
}
let subtract = function() {
console.log(arguments);
return arguments[0] - arguments[1];
}
console.log(sum(1, 2));
console.log(subtract(1, 2));
3
[Arguments] { '0': 1, '1': 2 }
-1
function Rectangle(a, b) {
this.a = a;
this.b = b;
}
const r = new Rectangle(2, 3);
console.log(r.a);
2
function Rectangle(a, b) {
this.a = a;
this.b = b;
}
// jede Funktion besitzt einen Prototypen
Rectangle.prototype.getArea = function() {
return this.a * this.b;
}
const r1 = new Rectangle(2, 3);
const r2 = new Rectangle(4, 5);
console.log(r1.getArea());
console.log(r2.getArea());
6
20
function Rectangle(a, b) {
this.a = a;
this.b = b;
}
const r = new Rectangle(2, 3);
console.log(r.getArea);
Rectangle.prototype.getArea = function() {
return this.a * this.b;
}
console.log(r.getArea);
undefined
[Function (anonymous)]
const a = [1, 2, 3];
console.log(a.sum());
6
Array.prototype.sum = function() {
let sum = 0;
for (let number of this) {
sum += number;
}
return sum;
}
// Oberklasse
function Shape() {
}
Shape.prototype.getType = function() {
return "Shape";
}
// Unterklasse
function Rectangle(a, b) {
this.a = a;
this.b = b;
}
// Prototype der Oberklasse in die Unterklasse kopieren
Rectangle.prototype = Object.create(Shape.prototype);
// Konstruktor der Oberklasse am Prototypen durch den eigenen ersetzen
Rectangle.prototype.constructor = Rectangle;
const r = new Rectangle(2, 3);
console.log(r.getType());
// .getType() selber implementieren
Rectangle.prototype.getType = function() {
return "Rectangle";
}
console.log(r.getType());
Shape
Rectangle
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push
class Rectangle {
constructor(a, b) {
this.a = a;
this.b = b;
}
getArea() {
return this.a * this.b;
}
}
const r = new Rectangle(2, 3);
console.log(r.getArea());
6
// Oberklasse
class Shape {
getType() {
return "Shape";
}
}
// Unterklasse erbt von Oberklasse
class Rectangle extends Shape {
constructor(a, b) {
super();
this.a = a;
this.b = b;
}
}
const r = new Rectangle(2, 3);
console.log(r.getType());
// Implementierung per Prototype weiterhin möglich, falls man so will
Rectangle.prototype.getType = function() {
return "Rectangle";
}
console.log(r.getType());
Shape
Rectangle
Asynchron: Es wird nicht auf die Beendigung des Befehls gewartet, sondern mit dem Programm fortgefahren. Die Vollendung des asynchronen Befehls tritt irgendwann in der Zukunft ein.
setTimeout(callback, time); // Ausführung nach [time] Millisekunden
setInterval(callback, interval); // Ausführung alle [interval] Millisekunden
setTimeout(function() {
// Code, der nach 2 Sekunden ausgeführt wird
console.log("zweiter");
}, 2000);
console.log("erster");
erster
zweiter
Aufgabe: Schreibe ein Programm, das zwei weitere beliebige Texte mit jeweils 2 Sekunden Verzögerung von einander ausgibt, d.h.
"erster" -> 2s -> "zweiter" -> 2s -> "Text A" -> 2s -> "Text B"
setTimeout(function() {
console.log("zweiter");
// weiterer Code
}, 2000);
console.log("erster");
setTimeout(function() {
console.log("zweiter");
setTimeout(function() {
console.log("Text A");
setTimeout(function() {
console.log("Text B");
}, 2000);
}, 2000);
}, 2000);
console.log("erster");
new Promise(function (resolve, reject) {
// ich bin fertig
resolve();
// es ist ein Fehler aufgetreten
reject();
});
const p = new Promise(function (resolve, reject) {...});
const p2 = new Promise(function (resolve, reject) {...});
const p3 = new Promise(function (resolve, reject) {...});
const p4 = new Promise(function (resolve, reject) {...});
p
.then(function() { return p2; })
.then(function() { return p3; })
.then(function() { return p4; });
console.log("erster");
delay(2000)
.then(function () {
console.log("zweiter");
return delay(2000);
})
.then(function() {
console.log("Text A");
return delay(2000);
})
.then(function() {
console.log("Text B");
})
const delay = function() {
// implementieren
}
console.log("erster");
delay(2000)
.then(function () {
console.log("zweiter");
return delay(2000);
})
.then(function() {
console.log("Text A");
return delay(2000);
})
.then(function() {
console.log("Text B");
})
const delay = function(ms) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, ms);
});
}
console.log("erster");
delay(2000)
.then(function () {
console.log("zweiter");
return delay(2000);
})
.then(function() {
console.log("Text A");
return delay(2000);
})
.then(function() {
console.log("Text B");
})
const p = new Promise(function(resolve, reject) {
resolve("ok");
});
p.then(function(value) {
console.log(value);
});
ok
const p = new Promise(function(resolve, reject) {
reject(new Error("Fehler"));
});
p
.then(function() {
console.log("Ich werde nicht aufgerufen")
})
.catch(function(e) {
console.log(e.message);
});
Fehler
const fs = require("fs");
fs.readFile("./hello.txt", {encoding: "utf8"}, function(error, data) {
console.log(data);
});
Hello World!
const fs = require("fs");
function readFile() {
// implementieren
}
readFile("./hello.txt").then(function(content) {
console.log(content);
});
Hello World!
const fs = require("fs");
function readFile(path) {
return new Promise(function (resolve, reject) {
fs.readFile(path, {encoding: "utf8"}, function(error, data) {
resolve(data);
});
});
}
readFile("./hello.txt").then(function(content) {
console.log(content);
});
Hello World!
Hello World!
Hallo Welt!
const fs = require("fs");
function readFile(path) {
return new Promise(function (resolve, reject) {
fs.readFile(path, {encoding: "utf8"}, function(error, data) {
resolve(data);
});
});
}
readFile("./hello.txt")
.then(function(content) {
console.log(content);
return readFile("./hallo.txt");
})
.then(function(content) {
console.log(content);
});
Hello World!
Hallo Welt!
await
nur im Kontext einer async
-Funktion möglich
async function wrapper() {
const p = new Promise(function(resolve, reject) {
resolve("Hello from Promise!");
});
const result = await p;
console.log(result);
}
wrapper();
Hello from Promise!
const fs = require("fs");
function readFile(path) {
return new Promise(function (resolve, reject) {
fs.readFile(path, {encoding: "utf8"}, function(error, data) {
resolve(data);
});
});
}
async function wrapper() {
const content1 = await readFile("./hello.txt");
const content2 = await readFile("./hallo.txt");
console.log(content1);
console.log(content2);
}
wrapper();
Hello World!
Hallo Welt!
Auflösen von komplexen Strukturen
// Objekt destrukturieren (per Attribut-Namen)
const { a, b } = { a: 1, b: 2 };
console.log(a);
console.log(b);
// Array destrukturieren (per Position)
const [ c, d ] = [3, 4];
console.log(c);
console.log(d);
1
2
3
4
// Bei Objekten Elemente umbenennen oder auch auslassen
const { a: x, b: y } = { a: 1, b: 2, c: 3 };
console.log(x);
console.log(y);
// Bei Arrays Elemente auslassen
const [ , a, b, , c] = [3, 4, 5, 6, 7, 8];
console.log(a);
console.log(b);
console.log(c);
1
2
4
5
7
// Verschachteltes Destructuring
const {a: [, x, ] } = { a: [0, 1, 2]};
console.log(x);
1
const o = { a: [0, {b: [0, 5]}, 2]};
const { /* Destructuring-Ausdruck */ } = o;
console.log(x);
5
const o = { a: [0, { b: [0, 5] }, 2]};
const { a: [, { b: [, x] }]} = o;
console.log(x);
5
const o = { a: [0, {b: [0, { c: [{ x: 5 }, { d: 3}] }]}, 2]};
const { /* Destructuring-Ausdruck */ } = o;
console.log(x);
3
const o = { a: [0, {b: [0, { c: [{ x: 5 }, { d: 3}] }]}, 2]};
const { a: [, {b: [, { c: [, { d: x}] }] }] } = o;
console.log(x);
3
Destructuring zum parallelen Ausführen von mehreren Promises
const fs = require("fs");
function readFile(path) {
return new Promise(function (resolve, reject) {
fs.readFile(path, {encoding: "utf8"}, function(error, data) {
resolve(data);
});
});
}
async function wrapper() {
const [ content1, content2 ] = await Promise.all([
readFile("./hello.txt"),
readFile("./hallo.txt")
]);
console.log(content1);
console.log(content2);
}
wrapper();
function throwError() {
try {
throw new Error("Fehler!");
return "Hello World!";
}
catch (e) {
return e.message;
}
finally {
console.log("Finally wird immer ausgeführt");
return "Finally!";
}
}
const result = throwError();
console.log(result);
Finally wird immer ausgeführt
Finally!
Anwendungsbeispiel für Try-Catch-Finally
function readFromDatabase() {
try {
db.connect();
return db.read();
}
catch (e) {
console.log(e.stack);
return "";
}
finally {
if (db.open) {
db.close();
}
}
}
function a() {
const x = 5;
return function() {
return x * x;
};
}
const squareX = a();
const result = squareX();
console.log(result);
25
class MyClass {
constructor(a) {
this.a = a;
}
getA() {
return this.a;
}
}
const x = new MyClass(5);
const y = new MyClass(10);
console.log(x.getA());
console.log(y.getA());
5
10
global.a = 5;
function foo() {
this.a += 10;
}
foo();
console.log(a);
15
class MyClass {
/* ... */
setA() {
function f() {
this.a += 100;
}
f();
}
}
const x = new MyClass(5);
x.setA();
console.log(x.getA());
TypeError: Cannot read property 'a' of undefined
class MyClass {
/* ... */
setA() {
const me = this;
function f() {
me.a += 100;
}
f();
}
}
const x = new MyClass(5);
x.setA();
console.log(x.getA());
105
return
nicht notwendig
// Einzeiler
const f1 = _ => 1;
const f2 = () => 1;
const f3 = (x) => x * x;
const f4 = (x, y) => x + y;
// Mehrzeiler
const f5 = (x, y) => {
return x * y;
};
class MyClass {
/* ... */
setA() {
const f = () => {
this.a += 100;
}
f();
}
}
const x = new MyClass(5);
x.setA();
console.log(x.getA());
105
function* generator() {
let i = 0;
while(true) {
yield i;
i++;
}
}
const g = generator();
console.log(g.next().value);
console.log(g.next().value);
console.log(g.next().value);
1
2
3
function* generator() {
yield 1;
yield 2;
yield 3;
}
const g = generator();
for (const i of g) {
console.log(i);
}
1
2
3
const revenues = [
{month: 0, revenue: 1000},
{month: 1, revenue: 2000},
{month: 2, revenue: 3000},
{month: 3, revenue: 4000},
{month: 4, revenue: 5000},
{month: 5, revenue: 6000},
{month: 6, revenue: 6000},
{month: 7, revenue: 5000},
{month: 8, revenue: 4000},
{month: 9, revenue: 3000},
{month: 10, revenue: 2000},
{month: 11, revenue: 1000}
];
let totalRevenue = 0;
/* ... */
console.log(totalRevenue);
totalRevenue = revenues
.filter((revenue) => revenue.month < 6)
.map((revenue) => revenue.amount)
.reduce((sum, amount) => sum + amount, 0);
21000
const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
a.filter((e) => e > 2); // Filterung
a.map((e) => e * 2); // Umformung
a.reduce((p, e) => p + e, 0); // Zusammenrechnung / Reduzierung
a.some((e) => e > 5); // true wenn min. ein Element die Bedingung erfüllt
a.every((e) => e > 5); // true wenn alle Elemente die Bedingung erfüllen
const m = new Map();
m.set("a", 0);
m.set("a", 1);
m.set("b", 2);
m.has("c"); // => false
m.delete("b");
console.log(m.get("a")); // => 1
m.forEach((k, v) => console.log(k, v)) // => "a" 1 ...
for (const entry of m.entries()) {
console.log(entry); // => ["a", 1] ...
}
for (const key of m.keys()) {
console.log(key); // => "a" ...
}
for (const value of m.values()) {
console.log(value); // => "1" ...
}
const s = new Set();
s.add("a");
s.add("a");
s.has("c"); // => false
s.delete("a");
console.log(s.size); // => 0
s.forEach((k, v) => console.log(k, v)) // => "a" "a" ...
for (const entry of m.entries()) {
console.log(entry); // => ["a", "a"] ...
}
for (const key of m.keys()) {
console.log(key); // => "a"...
}
for (const value of s.values()) {
console.log(value); // => "a" ...
}
function doSomething(e) {
console.log("capture");
}
function click(e) {
console.log("bubble");
}
div.addEventListener("click", doSomething, true);
button.addEventListener("click", click, false /* default */);
capturing
bubble
Aufgabe: Erweitere das vorherige Beispiel so, dass das div-Element einen weiteren Click-Handler bekommt, der den Text "bubble2" anzeigt, nachdem "bubble" in der Konsole geloggt wurde.
Erwartete Ausgabe:
capturing
bubble
bubble2
Lösung:
function doSomething(e) {
console.log("capture");
}
// neu
function doSomething2(e) {
console.log("bubble2");
}
function click(e) {
console.log("bubble");
}
div.addEventListener("click", doSomething, true);
div.addEventListener("click", doSomething2, false); // neu
button.addEventListener("click", click, false /* default */);
function click(e) {
e.stopPropagation()
}
Aufgabe: Ändere das Ergebnis des vorherigen Beispiels, sodass die Bubble-Phase auf Ebene des button-Elements gestoppt wird. Was ändert sich in der Ausgabe?
Lösung:
function doSomething(e) {
console.log("capture");
}
function doSomething2(e) {
console.log("bubble2");
}
function click(e) {
e.stopPropagation();
console.log("bubble");
}
div.addEventListener("click", doSomething, true);
div.addEventListener("click", doSomething2, false);
button.addEventListener("click", click, false /* default */);
button.dispatchEvent(new Event("click"));
doSomethingElse();
button.dispatchEvent(new Event("click"));
doAnotherThing(); // wird erst ausgeführt, wenn zuvor alle Event-Handler fertig sind
const empty1 = "";
const empty1 = '';
const s1 = 'abc';
const s2 = "abc";
const s3 = 'a"b"c';
const s4 = "a\"b\"c";
const s5 = 'a\'b\'c';
const s6 = "a'b'c";
const s7 = `a'b'"c"`;
const age = 10;
// Konkatenation
const s = "My age is " + number + "!";
// Interpolation
const s = `My age is ${number}!`;
// => "My age is 10!"
function sayHello() {
return "Hello";
}
let interpolation = `${sayHello()}`;
// => "Hello"
interpolation = `5 + 5 = ${5+5}`;
// => "5 + 5 = 10"
return html`hello world!`
function myTag() {
console.log(arguments);
// return 5;
// return true;
return "abc";
}
let interpolation = myTag`a ${5} b ${6} c`;
// => "abc"
Arguments(3) [Array(3), 5, 6]
0 : (3) ['a ', ' b ', ' c', raw: Array(3)]
1 : 5
2 : 6
Schreibe ein Tag, welches die Zahlen aus den dynamischen Ausdrücken zusammenrechnet (strings.js
)
function add(parts, ...numbers) {
return numbers.reduce((p, c) => p + c, 0);
}
let sum = add`a ${5} b ${6} c`;
console.log(sum);
// => 11
function add(...numbers) {
return numbers.reduce((p, c) => p + c, 0);
}
add(1, 2, 3); // => 6
const o1 = {a: 1, b: 2};
const o2 = {x: 5, y: 6, ...o1};
const a1 = [4, 5, 6];
const a2 = [1, 2, 3, ...a1];
window.innerWidth; // innere Auflösung des sichtbaren Fensters
window.innerHeight;
window.outerWidth; // äußere Auflösung des Browserfensters inklusive Adresszeile usw.
window.outerHeight;
window.addEventListener(); // Events an das äußerste "Dach"-Element hängen
location.href; // aktuelle URL
location.host; // aktuelle Domain, z.B. "www.google.de"
location.protocol; // aktuelles Protokoll, z.B. "https:"
navigator.language; // bevorzugte Browsersprache, z.B. "de"
navigator.userAgent; // z.B. "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) [...]"
navigator
.mediaDevices
.getDisplayMedia(); // Fordere Erlaubis zum Streamen von Anwendungen oder Bildschirmen an
document.body; // <body>-Element der Seite
document.activeElement; // aktives Element der Seite, welche gerade den Fokus besitzt
document.cookie; // für die aktuelle Seite gesetzte Cookies
document.execCommand("copy"); // Texte in die Zwischenablage zu schreiben
document.createElement("div"); // erzeuge neues DOM-Element mit angegebenen Tag
// auf 5MB Daten pro Domain begrenzt
localStorage.getItem(key); // Element holen
localStorage.setItem(key, value); // Element setzen
localStorage.removeItem(key); // Element entfernen
selector [, selector2, selector3, ...] {
property1: value;
property2: value;
}
html, body {
width: 100%;
height: 100%;
margin: 0;
}
/* Elemente */
html, body {...}
/* IDs */
#my-id {...}
/* Klassen */
.my-class {...}
/* Pseudo-Klassen */
div:hover {...}
/* Attribute */
div[my-attribut="abc"] {...}
/* Kombinationen */
div.my-class#my-id {...}
html {
--my-background-color: #abcdef;
}
html div {
background-color: var(--my-background-color, white);
}
display
-Attributblock
width
und height
möglichinline
Custom Elements
width
und height
nicht möglichinline-block
block
und inline
width
und height
möglichnone
position
-Attributstatic
relative
static
-Position, z.B. mittels left: 20px
absolut
static
-Parent (sonst window
)Implementiere folgendes Beispiel-Menü
.menu-item {
display: inline-block;
position: relative;
}
.menu-item .children {
display: none;
position: absolute;
}
.menu-item:hover .children {
display: block;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"></meta>
<meta
name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
>
</head>
<body>
...
</body>
</html>
Ein Muss für alle responsiven Seiten
npm install -g http-server
cd pfad/zum/projekt
http-server --port 8080
div {
width: 1px; /* Pixel */
width: 1pt; /* Points */
width: 1em; /* Breite des "M" in der Schriftgröße des Elements */
width: 1rem; /* Breite des "M" in der Schriftgröße des HTML-Elements */
width: 1vw; /* Prozent der View Width */
width: 1%; /* Prozent des Elternelements */
width: 5fr; /* Fraction (nur im CSS Grid verfügbar) */
}
Größeneinheiten in einer HTML-Datei ausprobieren
.container {
display: flex; /* soll ein flexibler Container sein */
display: inline-flex;
flex-direction: column; /* Kinder spaltenweise anordnen */
flex-direction: row; /* Kinder zeilenweise anordnen */
align-items: center;
justify-content: center;
gap: 20px; /* Abstände zwischen den Achsen */
}
.child {
flex-grow: 1; /* Anteiliger Platz, wenn mehr als nötig da ist */
flex-shrink: 1; /* Anteiliger Platz, wenn weniger als nötig da ist */
flex-basis: 20px; /* Grundlage zur Berechnung der finalen Größe */
order: 1; /* Erlaubt die Darstellung in anderer Reihenfolge als durch das HTML vorgegeben */
}
Mit CSS Flexbox rumspielen
.grid {
display: grid; /* inline-grid; */
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 5px 10px;
}
<div class="grid">
<span>A</span>
<span>B</span>
<span>C</span>
<span>D</span>
<span>E</span>
<span>F</span>
</div>
.grid {
grid-template-columns: [left] 1fr [column1] 1fr [column2] 1fr [right];
grid-template-rows: [top] 1fr [row1] 1fr [bottom];
}
.a {
grid-column: 2 / span 2;
grid-row: 1;
}
.b {
grid-column: left / column2;
grid-row: 2;
}
<div class="grid">
<span class="a">A</span>
<span class="b">B</span>
</div>
.grid {
grid-template-areas:
"header header header"
"content content content";
}
.a {
grid-area: header;
}
.b {
grid-area: 2 / 1 / 2 / 3; /* start-row / start-column / end-row / end-column */
/* alternativ auch Namen der Lines möglich */
}
Implementiere folgendes Design:
.grid {
display: grid;
grid-template-rows: 1fr 5fr 1fr;
gap: 2px;
grid-template-areas:
"navigation header header header"
"navigation content content content"
"footer footer footer footer"
}
.navigation {
grid-area: navigation;
}
.header {
grid-area: header;
}
.content {
grid-area: content;
}
.footer {
grid-area: footer;
}
<div class="grid">
<div class="area navigation">Navigation</div>
<div class="area header">Header</div>
<div class="area content">Content</div>
<div class="area footer">Footer</div>
</div>
.grid {
align-items: center;
justify-items: center;
}
@media screen and (min-width: 640px) and (max-width: 1024px) {
.navigation {
display: none;
}
}
Bedeutung: Wenn die Seite auf einem Display angezeigt wird, welches zwischen 640px und 1024px in der Breite anzeigen kann, dann blende die Navigation aus
Entwerfe eine kleine Seite mit @media und zeige ein beliebiges Element ab einer bestimmten Höhe oder Breite an (die Größe des Displays kann dynamisch mit den Entwicklertools im Gerätesimulator geändert werden)
Passe die Vorlage "media-queries-responsive-layout.html" mit @media-Queries so an, dass das Menü links ab einer maximalen Breite von 480 Pixel und kleiner nach links oben in die Ecke minimiert wird und nur per Hover wieder 50% Breite und 100% Höhe bekommt
@media screen and (max-width: 480px) {
.menu {
grid-area: unset;
position: absolute;
}
.menu:hover {
height: 100%;
width: 50%;
}
.grid {
grid-template-columns: 0fr 5fr;
}
}
.foo {
transform: translateX(20px) translateY(20px);
transform-origin: left;
}
Die meisten besitzen zusätzlich spezifischere X-, Y- oder 3D-Versionen
Probiere die genannten Transform-Effekte in einer beliebigen Seite aus
width
, height
, transform
, color
und viele weiteredisplay
lässt sich jedoch nicht animieren
.foo {
width: 100%;
background-color: red;
/* transition: [Attribut] [Dauer] [Zeitfunktion] */
transition: width 1s ease-out;
}
.foo:hover {
width: 50%;
}
Keyframes
.foo {
animation-duration: 3s;
animation-name: slidein;
}
@keyframes slidein {
from {
margin-left: 100%;
width: 300%;
}
to {
margin-left: 0%;
width: 100%;
}
}
.foo {
/* ... */
}
@keyframes slidein {
1% {
margin-left: 100%;
}
100% {
margin-left: 0%;
}
}
.container {
perspective: 1000px; /* "Entfernung" des Betrachters */
transform-style: preserve-3d; /* oder "flat" */
}
.element {
backface-visibility: hidden; /* oder "visible" */
}
Implementiere einen drehenden Würfel (Vorlage "templates/008-css/css-3d-cube.html")
Was sind Web Components?
Vorteile
Lasse die eigene Komponente "hello-sayer" auf eine Änderung des "name"-Attributs reagieren, indem der dort eingetragene Name in der Komponente angezeigt wird (Beispiel: name="Joe" => Hello Joe!)
(/examples/templates/web-components/hello-sayer.html)
<slot>
<slot>
s
Entwerfe eine CardComponent
(Vorlage "card-component.html") in folgendem Stil und nutze dabei sinnvolle <slot>
s:
Ein :host
-Block mit einem display
gehört zum guten Ton!
Innerhalb einer Komponente können beliebige Styles für verschiedene Selektoren verwendet werden
Welche Wechselwirkungen haben Styles zueinander, die innerhalb und außerhalb einer Komponente definiert sind? (Vorlage "web-component-styles.html")
Einige globale Styles werden dennoch vererbt:
inherit
besitzen (z.B. color
oder font-family
)--my-custom-color
Passe das vorherige Ergebnis (Vorlage "web-component-styles.html") so an, dass ein beliebiger Style per CSS-Variable von außen gesetzt werden kann (z.B. color
oder background-color
)
Erinnerung CSS-Variablen:
/* Definition */
html {
--my-variable: #abcdef;
}
/* Usage */
.my-class {
background-color: var(--my-variable, white);
}
In der Anfangszeit von Web Components wurde oft folgendes Muster zur Individualisierung verwendet:
/* Global Scope */
html {
--my-border-color: #abcdef;
--my-border-width: 1px;
--my-margin-top: 1rem;
--my-margin-bottom: 1rem;
}
/* Inside Web Component */
.container {
border-color: var(--my-border-color, white);
border-width: var(--my-border-width, 1px);
margin-top: var(--my-margin-top, 0.5rem);
margin-bottom: var(--my-margin-bottom, 0.5rem);
}
Eleganteres Stylen von Web Components mittels part
/* Global Scope */
my-component::part(inner) {
border-color: yellow;
border-width: 2px;
}
/* Inside Web Component */
Passe die CardComponent
aus einer vorherigen Übung an (Vorlage "card-component.html"), sodass man Titel und Inhalt einfach von außen per part
s stylen kann.
part
s von eingebetteten Web Components exportieren und verfügbar machen
Inner Text
Passe das Beispiel (Vorlage "exportparts.html") entsprechend an, sodass von außen sowohl der Inner Text
als auch der Outer Text
stylebar sind
Web Components können direkte Kinder, die via slot
eingefügt werden, stylen. Hierfür gibt es den Pseudo-Elemente-Selektor ::slotted([selector])
, welcher Elemente selektiert, die in einem Slot stecken:
/* Inside Web Component */
::slotted(*) { /* Selectors like elements, #id or .class */
font-style: italic;
}
Definiere mit dem Pseudo-Elemente-Selektor ::slotted()
Styles, sodass per slot
eingefügte Elemente mit der Klasse red
einen roten und Elemente mit der Klasse blue
einen blauen Hintergrund haben. Die Schriftart soll jeweils weiß sein (Vorlage "slotted.html")
dispatcht
werdenclick
bubbeln durch das Shadow Dom nach oben durchCustomEvent
muss entsprechend konfiguriert werden
button.dispatchEvent(new CustomEvent(
"tabactivated", // Name des Events, frei wählbar
{
detail: "any data", // beliebige Daten wie Strings, Zahlen, Booleans usw.
bubbles: true, // bestimmt, ob das Event durch alle Eltern nach oben steigt
cancelable: true, // Abbrechbar per event.preventDefault()
composed: true // durch eventuelle Shadow Root steigen, falls vorhanden.
}
));
Entwickle eine Tab-Komponente (Vorlage "tab-componenmt.html"), welche beim Click auf einen Registerreite / Tab ein Event feurt, welches die Außenwelt über das gerade aktivierte Tab (tab-id) informiert