Système solaire avec Three.js
Salut ! Aujourd'hui, je vais construire un système solaire en utilisant Three.js. Mais avant de commencer, sachez que l'inspiration de cet article est venue du représentant d'un client dont je travaille actuellement sur le projet. Oui, c'est vous, celui qui croit que la Terre est plate.
JavaScript/Node possède le plus grand écosystème de bibliothèques qui couvrent une énorme quantité de fonctionnalités qui simplifient votre développement, je peux donc toujours choisir celle qui convient le mieux à vos besoins. Cependant, si nous parlons de graphiques 3D, il n'y a pas beaucoup d'options intéressantes et three.js est probablement le meilleur de tous et possède la plus grande communauté.
Alors plongeons-nous dans Three.js et construisons le système solaire en l'utilisant. Dans cet article, je couvrirai :
- Initier le projet et la scène
- Création du Soleil
- Créer des planètes
- Déploiement sur les pages GitHub
Initier le projet et la scène
Tout d'abord : pour initialiser le projet, j'utilise Vite et j'installe la dépendance Three.js. Maintenant, la question est de savoir comment configurer Three.js. Pour cela, vous aurez besoin de trois choses : une scène, une caméra et un moteur de rendu. J'utilise également le module complémentaire intégré, OrbitControls, qui me permet de naviguer dans la scène. Après avoir démarré l'application, un écran noir devrait apparaître.
import { Scene, WebGLRenderer, PerspectiveCamera } from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
const w = window.innerWidth;
const h = window.innerHeight;
const scene = new Scene();
const camera = new PerspectiveCamera(75, w / h, 0.1, 100);
const renderer = new WebGLRenderer();
const controls = new OrbitControls(camera, renderer.domElement);
controls.minDistance = 10;
controls.maxDistance = 60;
camera.position.set(30 * Math.cos(Math.PI / 6), 30 * Math.sin(Math.PI / 6), 40);
renderer.setSize(w, h);
document.body.appendChild(renderer.domElement);
renderer.render(scene, camera);
window.addEventListener("resize", () => {
const w = window.innerWidth;
const h = window.innerHeight;
renderer.setSize(w, h);
camera.aspect = w / h;
camera.updateProjectionMatrix();
});
const animate = () => {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
};
animate();
Vous remarquerez peut-être que je limite le zoom via les commandes et que je modifie également l'angle par défaut de la caméra. Cela sera utile pour afficher correctement la scène dans les prochaines étapes.
Il est maintenant temps d'ajouter un simple champ d'étoiles puisque notre système solaire devrait être entouré d'étoiles. Pour simplifier l’explication, imaginez que vous avez une sphère et que vous choisissez 1 000 points aléatoires sur cette sphère. Ensuite, vous créez des étoiles à partir de ces points en leur appliquant une texture d'étoile. Enfin, j'ajoute une animation pour faire tourner tous ces points autour de l'axe y. Avec cela, le champ d'étoiles est prêt à être ajouté à la scène.
import {
Group,
Color,
Points,
Vector3,
TextureLoader,
PointsMaterial,
BufferGeometry,
AdditiveBlending,
Float32BufferAttribute,
} from "three";
export class Starfield {
group;
loader;
animate;
constructor({ numStars = 1000 } = {}) {
this.numStars = numStars;
this.group = new Group();
this.loader = new TextureLoader();
this.createStarfield();
this.animate = this.createAnimateFunction();
this.animate();
}
createStarfield() {
let col;
const verts = [];
const colors = [];
const positions = [];
for (let i = 0; i < this.numStars; i += 1) {
let p = this.getRandomSpherePoint();
const { pos, hue } = p;
positions.push(p);
col = new Color().setHSL(hue, 0.2, Math.random());
verts.push(pos.x, pos.y, pos.z);
colors.push(col.r, col.g, col.b);
}
const geo = new BufferGeometry();
geo.setAttribute("position", new Float32BufferAttribute(verts, 3));
geo.setAttribute("color", new Float32BufferAttribute(colors, 3));
const mat = new PointsMaterial({
size: 0.2,
alphaTest: 0.5,
transparent: true,
vertexColors: true,
blending: AdditiveBlending,
map: this.loader.load("/solar-system-threejs/assets/circle.png"),
});
const points = new Points(geo, mat);
this.group.add(points);
}
getRandomSpherePoint() {
const radius = Math.random() * 25 + 25;
const u = Math.random();
const v = Math.random();
const theta = 2 * Math.PI * u;
const phi = Math.acos(2 * v - 1);
let x = radius * Math.sin(phi) * Math.cos(theta);
let y = radius * Math.sin(phi) * Math.sin(theta);
let z = radius * Math.cos(phi);
return {
pos: new Vector3(x, y, z),
hue: 0.6,
minDist: radius,
};
}
createAnimateFunction() {
return () => {
requestAnimationFrame(this.animate);
this.group.rotation.y += 0.00005;
};
}
getStarfield() {
return this.group;
}
}
L'ajout du champ d'étoiles est simple, simplement en utilisant la méthode add dans la classe de scène
const starfield = new Starfield().getStarfield(); scene.add(starfield);
En ce qui concerne les textures, vous pouvez retrouver toutes les textures utilisées dans ce projet dans le référentiel, dont le lien est lié à la fin de l'article. La plupart des textures ont été tirées de ce site, à l'exception des textures des anneaux d'étoiles et de planètes.
Création du soleil
Pour le soleil, j'ai utilisé la géométrie de l'icosaèdre et y ai mappé une texture. En utilisant le bruit amélioré, j'ai obtenu un effet où le soleil pulse, simulant la façon dont une vraie étoile émet des flux d'énergie dans l'espace. Le soleil n'est pas seulement une figure avec une texture cartographiée ; il doit également s'agir d'une source de lumière dans la scène, j'utilise donc PointLight pour simuler cela.
import {
Mesh,
Group,
Color,
Vector3,
BackSide,
PointLight,
TextureLoader,
ShaderMaterial,
AdditiveBlending,
DynamicDrawUsage,
MeshBasicMaterial,
IcosahedronGeometry,
} from "three";
import { ImprovedNoise } from "three/addons/math/ImprovedNoise.js";
export class Sun {
group;
loader;
animate;
corona;
sunRim;
glow;
constructor() {
this.sunTexture = "/solar-system-threejs/assets/sun-map.jpg";
this.group = new Group();
this.loader = new TextureLoader();
this.createCorona();
this.createRim();
this.addLighting();
this.createGlow();
this.createSun();
this.animate = this.createAnimateFunction();
this.animate();
}
createSun() {
const map = this.loader.load(this.sunTexture);
const sunGeometry = new IcosahedronGeometry(5, 12);
const sunMaterial = new MeshBasicMaterial({
map,
emissive: new Color(0xffff99),
emissiveIntensity: 1.5,
});
const sunMesh = new Mesh(sunGeometry, sunMaterial);
this.group.add(sunMesh);
this.group.add(this.sunRim);
this.group.add(this.corona);
this.group.add(this.glow);
this.group.userData.update = (t) => {
this.group.rotation.y = -t / 5;
this.corona.userData.update(t);
};
}
createCorona() {
const coronaGeometry = new IcosahedronGeometry(4.9, 12);
const coronaMaterial = new MeshBasicMaterial({
color: 0xff0000,
side: BackSide,
});
const coronaMesh = new Mesh(coronaGeometry, coronaMaterial);
const coronaNoise = new ImprovedNoise();
let v3 = new Vector3();
let p = new Vector3();
let pos = coronaGeometry.attributes.position;
pos.usage = DynamicDrawUsage;
const len = pos.count;
const update = (t) => {
for (let i = 0; i < len; i += 1) {
p.fromBufferAttribute(pos, i).normalize();
v3.copy(p).multiplyScalar(5);
let ns = coronaNoise.noise(
v3.x + Math.cos(t),
v3.y + Math.sin(t),
v3.z + t
);
v3.copy(p)
.setLength(5)
.addScaledVector(p, ns * 0.4);
pos.setXYZ(i, v3.x, v3.y, v3.z);
}
pos.needsUpdate = true;
};
coronaMesh.userData.update = update;
this.corona = coronaMesh;
}
createGlow() {
const uniforms = {
color1: { value: new Color(0x000000) },
color2: { value: new Color(0xff0000) },
fresnelBias: { value: 0.2 },
fresnelScale: { value: 1.5 },
fresnelPower: { value: 4.0 },
};
const vertexShader = `
uniform float fresnelBias;
uniform float fresnelScale;
uniform float fresnelPower;
varying float vReflectionFactor;
void main() {
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
vec3 worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );
vec3 I = worldPosition.xyz - cameraPosition;
vReflectionFactor = fresnelBias + fresnelScale * pow( 1.0 + dot( normalize( I ), worldNormal ), fresnelPower );
gl_Position = projectionMatrix * mvPosition;
}
`;
const fragmentShader = `
uniform vec3 color1;
uniform vec3 color2;
varying float vReflectionFactor;
void main() {
float f = clamp( vReflectionFactor, 0.0, 1.0 );
gl_FragColor = vec4(mix(color2, color1, vec3(f)), f);
}
`;
const sunGlowMaterial = new ShaderMaterial({
uniforms,
vertexShader,
fragmentShader,
transparent: true,
blending: AdditiveBlending,
});
const sunGlowGeometry = new IcosahedronGeometry(5, 12);
const sunGlowMesh = new Mesh(sunGlowGeometry, sunGlowMaterial);
sunGlowMesh.scale.setScalar(1.1);
this.glow = sunGlowMesh;
}
createRim() {
const uniforms = {
color1: { value: new Color(0xffff99) },
color2: { value: new Color(0x000000) },
fresnelBias: { value: 0.2 },
fresnelScale: { value: 1.5 },
fresnelPower: { value: 4.0 },
};
const vertexShader = `
uniform float fresnelBias;
uniform float fresnelScale;
uniform float fresnelPower;
varying float vReflectionFactor;
void main() {
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
vec3 worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );
vec3 I = worldPosition.xyz - cameraPosition;
vReflectionFactor = fresnelBias + fresnelScale * pow( 1.0 + dot( normalize( I ), worldNormal ), fresnelPower );
gl_Position = projectionMatrix * mvPosition;
}
`;
const fragmentShader = `
uniform vec3 color1;
uniform vec3 color2;
varying float vReflectionFactor;
void main() {
float f = clamp( vReflectionFactor, 0.0, 1.0 );
gl_FragColor = vec4(mix(color2, color1, vec3(f)), f);
}
`;
const sunRimMaterial = new ShaderMaterial({
uniforms,
vertexShader,
fragmentShader,
transparent: true,
blending: AdditiveBlending,
});
const sunRimGeometry = new IcosahedronGeometry(5, 12);
const sunRimMesh = new Mesh(sunRimGeometry, sunRimMaterial);
sunRimMesh.scale.setScalar(1.01);
this.sunRim = sunRimMesh;
}
addLighting() {
const sunLight = new PointLight(0xffff99, 1000);
sunLight.position.set(0, 0, 0);
this.group.add(sunLight);
}
createAnimateFunction() {
return (t = 0) => {
const time = t * 0.00051;
requestAnimationFrame(this.animate);
this.group.userData.update(time);
};
}
getSun() {
return this.group;
}
}
Créer des planètes
Toutes les planètes sont construites selon une logique similaire : chaque planète a besoin d'une orbite, d'une texture, d'une vitesse d'orbite et d'une vitesse de rotation. Pour les planètes qui en ont besoin, des anneaux doivent également être ajoutés.
import {
Mesh,
Color,
Group,
DoubleSide,
RingGeometry,
TorusGeometry,
TextureLoader,
ShaderMaterial,
SRGBColorSpace,
AdditiveBlending,
MeshPhongMaterial,
MeshBasicMaterial,
IcosahedronGeometry,
} from "three";
export class Planet {
group;
loader;
animate;
planetGroup;
planetGeometry;
constructor({
orbitSpeed = 1,
orbitRadius = 1,
orbitRotationDirection = "clockwise",
planetSize = 1,
planetAngle = 0,
planetRotationSpeed = 1,
planetRotationDirection = "clockwise",
planetTexture = "/solar-system-threejs/assets/mercury-map.jpg",
rimHex = 0x0088ff,
facingHex = 0x000000,
rings = null,
} = {}) {
this.orbitSpeed = orbitSpeed;
this.orbitRadius = orbitRadius;
this.orbitRotationDirection = orbitRotationDirection;
this.planetSize = planetSize;
this.planetAngle = planetAngle;
this.planetTexture = planetTexture;
this.planetRotationSpeed = planetRotationSpeed;
this.planetRotationDirection = planetRotationDirection;
this.rings = rings;
this.group = new Group();
this.planetGroup = new Group();
this.loader = new TextureLoader();
this.planetGeometry = new IcosahedronGeometry(this.planetSize, 12);
this.createOrbit();
this.createRings();
this.createPlanet();
this.createGlow(rimHex, facingHex);
this.animate = this.createAnimateFunction();
this.animate();
}
createOrbit() {
const orbitGeometry = new TorusGeometry(this.orbitRadius, 0.01, 100);
const orbitMaterial = new MeshBasicMaterial({
color: 0xadd8e6,
side: DoubleSide,
});
const orbitMesh = new Mesh(orbitGeometry, orbitMaterial);
orbitMesh.rotation.x = Math.PI / 2;
this.group.add(orbitMesh);
}
createPlanet() {
const map = this.loader.load(this.planetTexture);
const planetMaterial = new MeshPhongMaterial({ map });
planetMaterial.map.colorSpace = SRGBColorSpace;
const planetMesh = new Mesh(this.planetGeometry, planetMaterial);
this.planetGroup.add(planetMesh);
this.planetGroup.position.x = this.orbitRadius - this.planetSize / 9;
this.planetGroup.rotation.z = this.planetAngle;
this.group.add(this.planetGroup);
}
createGlow(rimHex, facingHex) {
const uniforms = {
color1: { value: new Color(rimHex) },
color2: { value: new Color(facingHex) },
fresnelBias: { value: 0.2 },
fresnelScale: { value: 1.5 },
fresnelPower: { value: 4.0 },
};
const vertexShader = `
uniform float fresnelBias;
uniform float fresnelScale;
uniform float fresnelPower;
varying float vReflectionFactor;
void main() {
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
vec3 worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal );
vec3 I = worldPosition.xyz - cameraPosition;
vReflectionFactor = fresnelBias + fresnelScale * pow( 1.0 + dot( normalize( I ), worldNormal ), fresnelPower );
gl_Position = projectionMatrix * mvPosition;
}
`;
const fragmentShader = `
uniform vec3 color1;
uniform vec3 color2;
varying float vReflectionFactor;
void main() {
float f = clamp( vReflectionFactor, 0.0, 1.0 );
gl_FragColor = vec4(mix(color2, color1, vec3(f)), f);
}
`;
const planetGlowMaterial = new ShaderMaterial({
uniforms,
vertexShader,
fragmentShader,
transparent: true,
blending: AdditiveBlending,
});
const planetGlowMesh = new Mesh(this.planetGeometry, planetGlowMaterial);
planetGlowMesh.scale.setScalar(1.1);
this.planetGroup.add(planetGlowMesh);
}
createRings() {
if (!this.rings) return;
const innerRadius = this.planetSize + 0.1;
const outerRadius = innerRadius + this.rings.ringsSize;
const ringsGeometry = new RingGeometry(innerRadius, outerRadius, 32);
const ringsMaterial = new MeshBasicMaterial({
side: DoubleSide,
transparent: true,
map: this.loader.load(this.rings.ringsTexture),
});
const ringMeshs = new Mesh(ringsGeometry, ringsMaterial);
ringMeshs.rotation.x = Math.PI / 2;
this.planetGroup.add(ringMeshs);
}
createAnimateFunction() {
return () => {
requestAnimationFrame(this.animate);
this.updateOrbitRotation();
this.updatePlanetRotation();
};
}
updateOrbitRotation() {
if (this.orbitRotationDirection === "clockwise") {
this.group.rotation.y -= this.orbitSpeed;
} else if (this.orbitRotationDirection === "counterclockwise") {
this.group.rotation.y += this.orbitSpeed;
}
}
updatePlanetRotation() {
if (this.planetRotationDirection === "clockwise") {
this.planetGroup.rotation.y -= this.planetRotationSpeed;
} else if (this.planetRotationDirection === "counterclockwise") {
this.planetGroup.rotation.y += this.planetRotationSpeed;
}
}
getPlanet() {
return this.group;
}
}
Pour la Terre, j'étends la classe Planet pour ajouter des textures supplémentaires, telles que des nuages et une texture nocturne pour le côté nocturne de la planète.
import {
Mesh,
AdditiveBlending,
MeshBasicMaterial,
MeshStandardMaterial,
} from "three";
import { Planet } from "./planet";
export class Earth extends Planet {
constructor(props) {
super(props);
this.createPlanetLights();
this.createPlanetClouds();
}
createPlanetLights() {
const planetLightsMaterial = new MeshBasicMaterial({
map: this.loader.load("/solar-system-threejs/assets/earth-map-2.jpg"),
blending: AdditiveBlending,
});
const planetLightsMesh = new Mesh(
this.planetGeometry,
planetLightsMaterial
);
this.planetGroup.add(planetLightsMesh);
this.group.add(this.planetGroup);
}
createPlanetClouds() {
const planetCloudsMaterial = new MeshStandardMaterial({
map: this.loader.load("/solar-system-threejs/assets/earth-map-3.jpg"),
transparent: true,
opacity: 0.8,
blending: AdditiveBlending,
alphaMap: this.loader.load(
"/solar-system-threejs/assets/earth-map-4.jpg"
),
});
const planetCloudsMesh = new Mesh(
this.planetGeometry,
planetCloudsMaterial
);
planetCloudsMesh.scale.setScalar(1.003);
this.planetGroup.add(planetCloudsMesh);
this.group.add(this.planetGroup);
}
}
En cherchant sur Google pendant environ cinq minutes, vous tomberez sur un tableau avec toutes les valeurs nécessaires pour ajouter des planètes à la scène.
| Planet | Size (diameter) | Rotation speed | Rotation direction | Orbit speed |
|---|---|---|---|---|
| Mercury | 4,880 km | 10.83 km/h | Counterclockwise | 47.87 km/s |
| Venus | 12,104 km | 6.52 km/h | Clockwise | 35.02 km/s |
| Earth | 12,742 km | 1674.4 km/h | Counterclockwise | 29.78 km/s |
| Mars | 6,779 km | 866.5 km/h | Counterclockwise | 24.07 km/s |
| Jupiter | 142,984 km | 45,300 km/h | Counterclockwise | 13.07 km/s |
| Saturn | 120,536 km | 35,500 km/h | Counterclockwise | 9.69 km/s |
| Uranus | 51,118 km | 9,320 km/h | Clockwise | 6.81 km/s |
| Neptune | 49,528 km | 9,720 km/h | Counterclockwise | 5.43 km/s |
Now, all the planets and the sun can be added to the scene.
const planets = [
{
orbitSpeed: 0.00048,
orbitRadius: 10,
orbitRotationDirection: "clockwise",
planetSize: 0.2,
planetRotationSpeed: 0.005,
planetRotationDirection: "counterclockwise",
planetTexture: "/solar-system-threejs/assets/mercury-map.jpg",
rimHex: 0xf9cf9f,
},
{
orbitSpeed: 0.00035,
orbitRadius: 13,
orbitRotationDirection: "clockwise",
planetSize: 0.5,
planetRotationSpeed: 0.0005,
planetRotationDirection: "clockwise",
planetTexture: "/solar-system-threejs/assets/venus-map.jpg",
rimHex: 0xb66f1f,
},
{
orbitSpeed: 0.00024,
orbitRadius: 19,
orbitRotationDirection: "clockwise",
planetSize: 0.3,
planetRotationSpeed: 0.01,
planetRotationDirection: "counterclockwise",
planetTexture: "/solar-system-threejs/assets/mars-map.jpg",
rimHex: 0xbc6434,
},
{
orbitSpeed: 0.00013,
orbitRadius: 22,
orbitRotationDirection: "clockwise",
planetSize: 1,
planetRotationSpeed: 0.06,
planetRotationDirection: "counterclockwise",
planetTexture: "/solar-system-threejs/assets/jupiter-map.jpg",
rimHex: 0xf3d6b6,
},
{
orbitSpeed: 0.0001,
orbitRadius: 25,
orbitRotationDirection: "clockwise",
planetSize: 0.8,
planetRotationSpeed: 0.05,
planetRotationDirection: "counterclockwise",
planetTexture: "/solar-system-threejs/assets/saturn-map.jpg",
rimHex: 0xd6b892,
rings: {
ringsSize: 0.5,
ringsTexture: "/solar-system-threejs/assets/saturn-rings.jpg",
},
},
{
orbitSpeed: 0.00007,
orbitRadius: 28,
orbitRotationDirection: "clockwise",
planetSize: 0.5,
planetRotationSpeed: 0.02,
planetRotationDirection: "clockwise",
planetTexture: "/solar-system-threejs/assets/uranus-map.jpg",
rimHex: 0x9ab6c2,
rings: {
ringsSize: 0.4,
ringsTexture: "/solar-system-threejs/assets/uranus-rings.jpg",
},
},
{
orbitSpeed: 0.000054,
orbitRadius: 31,
orbitRotationDirection: "clockwise",
planetSize: 0.5,
planetRotationSpeed: 0.02,
planetRotationDirection: "counterclockwise",
planetTexture: "/solar-system-threejs/assets/neptune-map.jpg",
rimHex: 0x5c7ed7,
},
];
planets.forEach((item) => {
const planet = new Planet(item).getPlanet();
scene.add(planet);
});
const earth = new Earth({
orbitSpeed: 0.00029,
orbitRadius: 16,
orbitRotationDirection: "clockwise",
planetSize: 0.5,
planetAngle: (-23.4 * Math.PI) / 180,
planetRotationSpeed: 0.01,
planetRotationDirection: "counterclockwise",
planetTexture: "/solar-system-threejs/assets/earth-map-1.jpg",
}).getPlanet();
scene.add(earth);
In result all solar system will look sth like:
Deploying to GitHub Pages
For deploying to set the correct base in vite.config.js.
If you are deploying to https://
If you are deploying to https://
Go to your GitHub Pages configuration in the repository settings page and choose the source of deployment as "GitHub Actions", this will lead you to create a workflow that builds and deploys your project, a sample workflow that installs dependencies and builds using npm is provided:
# Simple workflow for deploying static content to GitHub Pages
name: Deploy static content to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ['main']
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets the GITHUB_TOKEN permissions to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow one concurrent deployment
concurrency:
group: 'pages'
cancel-in-progress: true
jobs:
# Single deploy job since we're just deploying
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
# Upload dist folder
path: './dist'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
That is it. If your deployment has not started automatically you can always start it manually in Actions tab in your repo. Link with deployed project can be found below.
Conclusion
That’s it for today! You can find the link to the entire project below. I hope you found this entertaining and don’t still believe the Earth is flat.
See ya!
Repository link
Deployment link
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!
Outils d'IA chauds
Undress AI Tool
Images de déshabillage gratuites
Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes
AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.
Clothoff.io
Dissolvant de vêtements AI
Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !
Article chaud
Outils chauds
Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit
SublimeText3 version chinoise
Version chinoise, très simple à utiliser
Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP
Dreamweaver CS6
Outils de développement Web visuel
SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)
Appareils et contextes avancés JavaScript
Jul 24, 2025 am 12:42 AM
La portée de JavaScript détermine la portée d'accessibilité des variables, qui sont divisées en étendue globale, fonction et au niveau du bloc; Le contexte détermine la direction de cela et dépend de la méthode d'appel de fonction. 1. Les étendues incluent la portée globale (accessible n'importe où), la portée de la fonction (valide uniquement dans la fonction) et la portée au niveau du bloc (LET et const sont valides dans {}). 2. Le contexte d'exécution contient l'objet variable, la chaîne de portée et les valeurs de cela. Cela pointe vers global ou non défini dans la fonction ordinaire, l'appel de méthode pointe vers l'objet d'appel, le constructeur pointe vers le nouvel objet, et peut également être explicitement spécifié par appel / application / liaison. 3. La fermeture fait référence aux fonctions accédant et en se souvenant des variables de portée externes. Ils sont souvent utilisés pour l'encapsulation et le cache, mais peuvent provoquer
API de composition Vue 3 Vs API Options: une comparaison détaillée
Jul 25, 2025 am 03:46 AM
CompositionAPI dans Vue3 convient plus à la logique complexe et à la dérivation de type, et OptionsAPI convient aux scénarios et débutants simples; 1. OptionsAPI organise le code en fonction d'options telles que les données et les méthodes, et a une structure claire mais les composants complexes sont fragmentés; 2. CompositionAPI utilise la configuration pour concentrer la logique liée, ce qui est propice à la maintenance et à la réutilisation; 3. CompositionAPI réalise la réutilisation logique sans conflit et paramétrisable par le biais de fonctions composables, ce qui est mieux que le mixin; 4. CompositionAPI a une meilleure prise en charge de la dérivation de type dactylographiée et de type plus précise; 5. Il n'y a pas de différence significative dans le volume de performances et d'emballage des deux; 6.
Exploration des règles de coercition de type en javascript
Jul 21, 2025 am 02:31 AM
La coulée de type est le comportement de la conversion automatique d'un type de valeur en un autre type en JavaScript. Les scénarios courants incluent: 1. Lorsque vous utilisez des opérateurs, si un côté est une chaîne, l'autre côté sera également converti en une chaîne, comme '5' 5. Le résultat est "55"; 2. Dans le contexte booléen, les valeurs non cooliennes seront implicitement converties en types booléens, tels que des chaînes vides, 0, nuls, non définies, etc., qui sont considérées comme fausses; 3. Null participe aux opérations numériques et sera convertie en 0, et non défini sera converti en NAN; 4. Les problèmes causés par la conversion implicite peuvent être évitées grâce à des fonctions de conversion explicites telles que Number (), String () et Boolean (). La maîtrise de ces règles aide
Maîtriser les modèles de concurrence JavaScript: les travailleurs du web contre les threads Java
Jul 25, 2025 am 04:31 AM
Il existe une différence essentielle entre les travailleurs Web de JavaScript et Javathreads dans un traitement simultané. 1. JavaScript adopte un modèle unique. WebWorkers est un fil indépendant fourni par le navigateur. Il convient pour effectuer des tâches longues qui ne bloquent pas l'interface utilisateur, mais ne peuvent pas utiliser le DOM; 2. Java prend en charge le multithreading réel à partir du niveau de la langue, créé via la classe de threads, adapté à un traitement simultanée complexe et côté serveur; 3. Les travailleurs Web utilisent PostMessage () pour communiquer avec le fil principal, qui est hautement sécurisé et isolé; Les threads Java peuvent partager la mémoire, de sorte que les problèmes de synchronisation doivent être prêts à prêter attention; 4. Les travailleurs Web sont plus adaptés à l'informatique parallèle frontale, comme le traitement d'image, et
Comment créer et ajouter des éléments dans JS?
Jul 25, 2025 am 03:56 AM
Utilisez Document.CreateElement () pour créer de nouveaux éléments; 2. Personnaliser les éléments via TextContent, ClassList, SetAttribute et d'autres méthodes; 3. Utilisez des méthodes APPEDCHILD () ou plus flexibles APPEND () pour ajouter des éléments au DOM; 4. Utiliser éventuellement INSERTBEFORE (), avant () et d'autres méthodes pour contrôler la position d'insertion; Le processus complet consiste à créer → Personnaliser → Ajouter, et vous pouvez mettre à jour dynamiquement le contenu de la page.
Comment formater une date dans JS?
Jul 20, 2025 am 12:10 AM
Les dates de format dans JavaScript peuvent être implémentées via des méthodes natives ou des bibliothèques tierces. 1. Utilisez des coutures d'objets à date native: Obtenez la partie de date via Gettillyar, Getmonth, GetDate et d'autres méthodes, et les épisser manuellement dans des formats Yyyy-MM et d'autres, qui conviennent aux besoins légers et ne reposent pas sur des bibliothèques tierces; 2. Utilisez la méthode TolocaleDateString: vous pouvez sortir tel que le format mm / dd / yyyy en fonction des habitudes locales, en charge multilingue, mais le format peut être incohérent en raison de différents environnements; 3. Utilisez des bibliothèques tierces telles que Day.js ou Date-FNS: Fournit une syntaxe concise et des fonctions riches, adaptées aux opérations fréquentes ou lorsque l'extensibilité est requise, comme DayJS ()
Construire un outil CLI avec Node.js
Jul 24, 2025 am 03:39 AM
Initialiser le projet et créer package.json; 2. Créez un script d'entrée index.js avec shebang; 3. Registre des commandes via des champs bin dans package.json; 4. Utilisez des Yargs et d'autres bibliothèques pour analyser les paramètres de ligne de commande; 5. Utilisez le test local NPMLink; 6. Ajouter l'aide, la version et les options pour améliorer l'expérience; 7. Publier éventuellement via NPMPublish; 8. Affectuer éventuellement l'achèvement automatique avec Yargs; Enfin, créez des outils CLI pratiques grâce à une structure raisonnable et à une conception de l'expérience utilisateur, effectuer des tâches d'automatisation ou distribuer des widgets et se terminer par des phrases complètes.
Types conditionnels avancés en dactylographie
Aug 04, 2025 am 06:32 AM
Les types de conditions avancées de TypeScript implémentent le jugement logique entre les types via TextendU? X: Y Syntaxe. Ses capacités de base se reflètent dans les types de conditions distribuées, l'inférence de type inférieure et la construction d'outils de type complexe. 1. Le type conditionnel est distribué dans les paramètres de type nu et peut automatiquement diviser le type de joint, tel que pour obtenir la chaîne [] | nombre []. 2. Utiliser la distribution pour construire des outils de filtrage et d'extraction: exclut exclut les types via TextendU? Never: T, extraire extrait les points communs via TextendU? T: jamais, et des filtres non nuls nuls / non définis. 3


