首页 > 其他分享 >【Three.JS零基础入门教程】第六篇:物体详解

【Three.JS零基础入门教程】第六篇:物体详解

时间:2024-08-16 13:55:12浏览次数:9  
标签:const 入门教程 THREE Three window renderer new JS data

 前期回顾:

【Three.JS零基础入门教程】第一篇:搭建开发环境

【Three.JS零基础入门教程】第二篇:起步案例

【Three.JS零基础入门教程】第三篇:开发辅助

【Three.JS零基础入门教程】第四篇:基础变换

【Three.JS零基础入门教程】第五篇:项目规划


下面将进一步详解介绍Threejs中的常用对象, 包括:

  • 物体
    • 几何
    • 材质
    • 纹理
  • 场景
  • 相机
  • 光线与阴影(付费)
  • 加载外部模型(付费)
  • 粒子效果(付费)
  • 动画与交互(付费)
  • 物理仿真(付费)

本篇内容主要介绍物体基本原理(几何、材质和纹理)和几种几何体(立方体、平面、球体)的讲解。

其他的将在后续的更新中逐一介绍。

简介

如何在虚拟的3D场景中模拟真实世界, 核心是物体

three.js中, 物体使用Mesh(网格)来描述

网格模型

在计算机图形学中, 几何体都是由三角形拼接而成, 由三角形组成的模型叫网格模型

从上面可以看到, 三角形越多, 模拟的模型越接近真实情况。

ChatGPT的解释

图形学中使用三角形作为基本的构造单元来生成复杂的物体,这是因为使用三角形可以带来多方面的好处。下面是一些主要的好处:

  1. 易于处理:三角形是一种简单的几何图形,易于计算和处理。它们有三个顶点,每个顶点有三个坐标,这使它们易于表示和存储。
  2. 适合多边形的形状:复杂的多边形形状可以通过简单的三角形组合来近似表示。这种近似往往能够满足需要,同时也可以提高计算效率。
  3. 易于进行光照和渲染:计算机图形学中的光照和渲染算法通常是针对三角形的。这是因为三角形是最简单的几何形状之一,它们的光照和渲染可以在多个工具和库中找到。
  4. 具有一致性:使用三角形作为构造单元可以带来一致性的好处。因为三角形是通用的基本几何形状,它们可以被用于不同的场景和应用中,从简单的2D图形到复杂的3D物体,这样可以使代码更加通用。
  5. 确保物体的平面:在三维空间中,三角形是唯一可以确保与另一个三角形在同一平面上的几何形状。这是因为只要三个点不共线,就可以构建出确定的平面,这保障了物体的正确表现。

综上,使用三角形作为构造单元有多种好处,使得其成为图形学中最受欢迎的几何形状之一。

Mesh主要由这些部分组成

  • 几何
  • 材质
  • 纹理

1. 几何

如何理解几何?

几何描述了物体的形状大小, 比如同样是桌子形状大小就各不相同

  • 形状上: 有方形的, 圆形的
  • 大小上: 有大的, 有小的

2. 材质

如何理解材质?

材质就是物体使用的材料, 材质不同对光线的反射效果不同

还是以桌子以例, 不同的桌面有的是木头, 有的是大理石, 有的是塑料(复合材料), 有的是金属

再比如, 门有木门铁门玻璃门

3. 纹理

如何理解纹理?

纹理就是物体表面的图案花纹

还是以桌子为例, 不同木头, 表面的花纹不一样

几何详解

threejs中给我们内置了一些几何形状, 具体内容参见文档

docs中搜索geometry几何体

这里, 我们主要介绍几个常用的几何体(立方体, 球体, 平面)

1. 立方体

立方体, 我们主要需要设置其(长宽高)属性值

  • 长(width): x轴所占据的空间
  • 宽(depth): z轴所占据的空间
  • 高(height): y轴所占据的空间
// 三. 创建物体
const cubeGeometry = new THREE.BoxGeometry(2, 2, 2)
const cubeMaterial = new THREE.MeshNormalMaterial()
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
scene.add(cube)

为了方便观察, 我们可以考虑使用Gui工具, 调整立方体的坐标和大小

完整示例:

// 导入threejs
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import * as dat from 'dat.gui'

// 一. 创建场景
const scene = new THREE.Scene()

// 二. 创建相机
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight
)
camera.position.set(20, 20, 20)
camera.lookAt(0, 0, 0)

// 三. 创建物体
const cubeGeometry = new THREE.BoxGeometry(2, 2, 2)
const cubeMaterial = new THREE.MeshNormalMaterial()
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
scene.add(cube)

// 六. 集成Gui工具
const gui = new dat.GUI()
const data = {
  x: 0,
  y: 0,
  z: 0,
  width: 2,
  height: 2,
  depth: 2,
}
gui.add(data, 'x').onChange((value) => {
  cube.position.x = value
})
gui.add(data, 'y').onChange((value) => {
  cube.position.y = value
})
gui.add(data, 'z').onChange((value) => {
  cube.position.z = value
})
gui.add(data, 'width', 2, 20, 1).onChange((value) => {
  data.width = value
  // 销毁旧的几何体体
  cube.geometry.dispose()
  cube.geometry = new THREE.BoxGeometry(data.width, data.height, data.depth)
})
gui.add(data, 'height', 2, 20, 1).onChange((value) => {
  data.height = value
  // 销毁旧的几何体体
  cube.geometry.dispose()
  cube.geometry = new THREE.BoxGeometry(data.width, data.height, data.depth)
})
gui.add(data, 'depth', 2, 20, 1).onChange((value) => {
  data.depth = value
  // 销毁旧的几何体体
  cube.geometry.dispose()
  cube.geometry = new THREE.BoxGeometry(data.width, data.height, data.depth)
})
// 四. 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setAnimationLoop(animation)
document.body.appendChild(renderer.domElement)

function animation() {
  renderer.render(scene, camera)
}

window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()

  renderer.setSize(window.innerWidth, window.innerHeight)
})
// 五. 集成辅助工具
const control = new OrbitControls(camera, renderer.domElement)

const axesHepler = new THREE.AxesHelper(10)
scene.add(axesHepler)

const gridHelper = new THREE.GridHelper(20, 20, 0xffffff, 0xffffff)
gridHelper.material.transparent = true
gridHelper.material.opacity = 0.5
scene.add(gridHelper)

2. 球体

球体, 我们主要修改其半径和分段

  • 半径(radius): 球体半径
  • 经线分段数(widthSegments):
  • 纬线分段数(heightSegments):
const sphereGeometry = new THREE.SphereGeometry(1, 32, 32)
const sphereMaterial = new THREE.MeshNormalMaterial()
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial)

完整示例:

import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'

import * as dat from 'dat.gui'

// 一. 创建场景
const scene = new THREE.Scene()

// 二. 创建相机
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight
)
camera.position.set(0, 0, 5)

// 三. 创建物体
const sphereGeometry = new THREE.SphereGeometry(1, 32, 32)
const sphereMaterial = new THREE.MeshNormalMaterial()
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial)
scene.add(sphere)

const data = {
  x: 0,
  y: 0,
  z: 0,
  radius: 1,
  widthSegments: 32,
  heightSegments: 32,
}
const gui = new dat.GUI()
gui.add(data, 'x').onChange((value) => {
  sphere.position.x = value
})
gui.add(data, 'y').onChange((value) => {
  sphere.position.y = value
})
gui.add(data, 'z').onChange((value) => {
  sphere.position.z = value
})
gui.add(data, 'radius', 1, 10, 1).onChange((value) => {
  data.radius = value
  sphere.geometry.dispose()
  sphere.geometry = new THREE.SphereGeometry(
    data.radius,
    data.widthSegments,
    data.heightSegments
  )
})
gui.add(data, 'widthSegments', 3, 64, 1).onChange((value) => {
  data.widthSegments = value
  sphere.geometry.dispose()
  sphere.geometry = new THREE.SphereGeometry(
    data.radius,
    data.widthSegments,
    data.heightSegments
  )
})
gui.add(data, 'heightSegments', 2, 64, 1).onChange((value) => {
  data.heightSegments = value
  sphere.geometry.dispose()
  sphere.geometry = new THREE.SphereGeometry(
    data.radius,
    data.widthSegments,
    data.heightSegments
  )
})

// 四. 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setAnimationLoop(animation)
// 将渲染的canvas添加到body元素中
document.body.appendChild(renderer.domElement)

// 五. 辅助工具
const control = new OrbitControls(camera, renderer.domElement)

const axesHelper = new THREE.AxesHelper(10)
scene.add(axesHelper)

const gridHelper = new THREE.GridHelper(20, 20, 0xffffff, 0xffffff)
gridHelper.material.transparent = true
gridHelper.material.opacity = 0.5
scene.add(gridHelper)

function animation() {
  renderer.render(scene, camera)
}

window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()

  renderer.setSize(window.innerWidth, window.innerHeight)
})

上面我们发现Gui部分的代码很多都是重复的。

考虑到后续其它对象也需要使用Gui工具, 我们可以考虑统一封装

创建src/gui文件夹

gui文件夹下创建index.js导出两个类

  • BaseGui
  • MeshGui
export { BaseGui } from './BaseGui'
export { MeshGui } from './MeshGui'
import * as dat from 'dat.gui'

export class BaseGui {
  constructor() {
    this.gui = new dat.GUI()
  }
  initGuiFolder(item, name, parent, config) {
    const folder = this.gui.addFolder(name)

    Object.keys(config).forEach((key) => {
      this.initGuiItem(folder, item, key, parent, config[key])
    })
  }
  initGuiItem(gui, item, key, parent, options = {}) {
    // 构造数据
    const controls = {}
    if (key === 'color') {
      controls[key] = item.color.getHex()
    } else {
      controls[key] = item[key]
    }

    // console.log(controls)

    const method = options.method || 'add'

    const min = options.min || (options.extend && options.extend[0])
    const max = options.max || (options.extend && options.extend[1])
    const step = options.step || 1
    const name = options.name

    let guiItem = gui[method](controls, key)

    if (guiItem.min && guiItem.max && guiItem.step) {
      guiItem = min !== undefined ? guiItem.min(min) : guiItem
      guiItem = max !== undefined ? guiItem.max(max) : guiItem
      guiItem = step !== undefined ? guiItem.step(step) : guiItem
    }

    guiItem = name !== undefined ? guiItem.name(name) : guiItem

    guiItem.onChange((value) => {
      if (options.handler) {
        options.handler(item, key, value, parent)
      } else {
        item[key] = value
      }
    })
  }
}

import * as THREE from 'three'

import { BaseGui } from './BaseGui'

function defaultHandler(item, key, value) {
  item[key] = value
}
const Vector3Config = {
  x: {
    handler: defaultHandler,
  },
  y: {
    handler: defaultHandler,
  },
  z: {
    handler: defaultHandler,
  },
}
function eulerHandler(item, key, value) {
  item[key] = THREE.MathUtils.degToRad(value)
}
const EulerConfig = {
  x: {
    extend: [-180, 180],
    handler: eulerHandler,
  },
  y: {
    extend: [-180, 180],
    handler: eulerHandler,
  },
  z: {
    extend: [-180, 180],
    handler: eulerHandler,
  },
}
function geometryHandler(item, key, value, parent) {
  const params = { ...parent.geometry.parameters }
  params[key] = value
  parent.geometry.dispose()
  parent.geometry = new THREE[parent.geometry.type](...Object.values(params))
}
const GeometryMapping = {
  BoxGeometry: {
    width: {
      name: 'x轴宽度',
      extend: [2, 20],
      handler: geometryHandler,
    },
    height: {
      name: 'y轴高度',
      extend: [2, 20],
      handler: geometryHandler,
    },
    depth: {
      name: 'z轴深度',
      extend: [2, 20],
      handler: geometryHandler,
    },
  },
  SphereGeometry: {
    radius: {
      name: '半径',
      min: 1,
      handler: geometryHandler,
    },
    widthSegments: {
      name: '水平分段数',
      min: 3,
      handler: geometryHandler,
    },
    heightSegments: {
      name: '垂直分段数',
      min: 2,
      handler: geometryHandler,
    },
  },
  PlaneGeometry: {
    width: {
      name: 'x轴宽度',
      min: 1,
      handler: geometryHandler,
    },
    height: {
      name: 'y轴高度',
      min: 1,
      handler: geometryHandler,
    },
  },
}

export class MeshGui extends BaseGui {
  constructor(options = {}) {
    if (!options.target.isMesh) {
      console.error('target must be an instance of Mesh')
      return
    }

    super()
    this.init(options)
  }
  init(options) {
    this.mesh = options.target
    this.geometry = this.mesh.geometry
    this.material = this.mesh.material

    this.position = this.mesh.position
    this.rotation = this.mesh.rotation
    this.scale = this.mesh.scale

    options.position !== false ? this.initPosition() : ''
    options.rotation !== false ? this.initRotation() : ''
    options.scale !== false ? this.initScale() : ''
    options.geometry !== false ? this.initGeometry() : ''
  }
  initPosition() {
    console.log(this.position)
    this.initGuiFolder(this.position, '位置', this.mesh, Vector3Config)
  }
  initRotation() {
    this.initGuiFolder(this.rotation, '旋转(度)', this.mesh, EulerConfig)
  }
  initScale() {
    this.initGuiFolder(this.scale, '缩放', this.mesh, Vector3Config)
  }
  initGeometry() {
    const geometry = this.geometry
    const type = geometry.type
    const config = GeometryMapping[type]
    this.initGuiFolder(geometry.parameters, geometry.type, this.mesh, config)
  }
}

完整示例(优化封装版)

在球体几何中引用MeshGui

// 导入threejs
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'

// 导入封装的Gui工具
import { MeshGui } from '../gui'

// 一. 创建场景
const scene = new THREE.Scene()

// 二. 创建相机
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight
)
camera.position.set(20, 20, 20)
camera.lookAt(0, 0, 0)

// 三. 创建物体
const sphereGeometry = new THREE.SphereGeometry(2)
const sphereMaterail = new THREE.MeshNormalMaterial() // 法向
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterail)
scene.add(sphere)

// 六. 集成Gui工具
new MeshGui({
  target: sphere,
})

// 四. 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setAnimationLoop(animation)
document.body.appendChild(renderer.domElement)

function animation() {
  renderer.render(scene, camera)
}

window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()

  renderer.setSize(window.innerWidth, window.innerHeight)
})
// 五. 集成辅助工具
const control = new OrbitControls(camera, renderer.domElement)

const axesHepler = new THREE.AxesHelper(10)
scene.add(axesHepler)

const gridHelper = new THREE.GridHelper(20, 20, 0xffffff, 0xffffff)
gridHelper.material.transparent = true
gridHelper.material.opacity = 0.5
scene.add(gridHelper)

3. 平面

对于平面, 主要设置

  • width: x轴方向的宽度
  • height: y轴方向的高度
const geometry = new THREE.PlaneGeometry(20, 20)
const material = new THREE.MeshBasicMaterial({ color: 0x333333 })

const plane = new THREE.Mesh(geometry, material)

完整示例:

import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'

import { MeshGui } from './gui'
// 一. 创建场景
const scene = new THREE.Scene()

// 二. 创建相机
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight
)
camera.position.set(0, 0, 5)

// 三. 创建物体
const geometry = new THREE.PlaneGeometry(20, 20)
const material = new THREE.MeshNormalMaterial()
const plane = new THREE.Mesh(geometry, material)
scene.add(plane)
new MeshGui({
  target: plane,
})

// 四. 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setAnimationLoop(animation)
// 将渲染的canvas添加到body元素中
document.body.appendChild(renderer.domElement)

// 五. 辅助工具
const control = new OrbitControls(camera, renderer.domElement)

const axesHelper = new THREE.AxesHelper(10)
scene.add(axesHelper)

const gridHelper = new THREE.GridHelper(20, 20, 0xffffff, 0xffffff)
gridHelper.material.transparent = true
gridHelper.material.opacity = 0.5
scene.add(gridHelper)

function animation() {
  renderer.render(scene, camera)
}

window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()

  renderer.setSize(window.innerWidth, window.innerHeight)
})

4. 缓冲区几何体

虽然three.js给我们内置了很多常用的几何体

但是对于一些没有提供的几何体如何处理呢?

比如, 像下图所示的几何体

这里, 我们可以通过基类BufferGeometry自定义几何体

缓冲区几何体

  1. 根据我们的几何常识: 连点成线, 连线成面, 连面成体
  2. 如果我们要渲染一个几何体, 只需要确定几何体的顶点坐标, 然后将这些点连接起来, 但是点太多, 为了方便管理我们使用一个缓冲区Buffer来存储, 因此自定义几何体也称缓冲区几何体

步骤

  1. 实例化BufferGeometry对象
  2. 定义顶点坐标缓冲区(数组), 数组中每3个元素为一组, 表示一点的坐标
  3. 设置几何体的position属性

示例

// 1. 创建缓冲区几何体对象
const geometry = new THREE.BufferGeometry()
// 2. 定义顶点坐标缓冲区
const vertices = new Float32Array([
  // 第一个三角形
  -1.0, -1.0, 1.0, 1.0, -1.0, 0, 1.0, 1.0, 1.0,
  // 第二个三角形
  -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 0,
])
// 3. 设置顶点坐标
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))

const material = new THREE.MeshBasicMaterial({
  color: 0xff0000,
  wireframe: true,
})

const mesh = new THREE.Mesh(geometry, material)

完整示例:

import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'

// 一. 创建场景
const scene = new THREE.Scene()

// 二. 创建相机
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight
)
camera.position.set(0, 0, 5)

// 三. 创建物体
// 根据顶点构建三角形
// 1. 创建缓冲区几何体对象
const geometry = new THREE.BufferGeometry()
// 2. 定义顶点坐标缓冲区
const vertices = new Float32Array([
  // 第一个三角形
  -1.0, -1.0, 1.0, 1.0, -1.0, 0, 1.0, 1.0, 1.0,
  // 第二个三角形
  -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 0,
])
// 3. 设置顶点坐标
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))

const material = new THREE.MeshBasicMaterial({
  color: 0xff0000,
  // wireframe: true,
})

const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)

// 四. 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setAnimationLoop(animation)
// 将渲染的canvas添加到body元素中
document.body.appendChild(renderer.domElement)

// 五. 辅助工具
const control = new OrbitControls(camera, renderer.domElement)

const axesHelper = new THREE.AxesHelper(10)
scene.add(axesHelper)

const gridHelper = new THREE.GridHelper(20, 20, 0xffffff, 0xffffff)
gridHelper.material.transparent = true
gridHelper.material.opacity = 0.5
scene.add(gridHelper)

function animation() {
  renderer.render(scene, camera)
}

window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()

  renderer.setSize(window.innerWidth, window.innerHeight)
})

需要视频版教程戳↓↓↓

GIS资料免费领icon-default.png?t=N7T8https://www.wjx.cn/vm/Qm8Ful2.aspx

标签:const,入门教程,THREE,Three,window,renderer,new,JS,data
From: https://blog.csdn.net/2401_84715637/article/details/141258031

相关文章

  • 【Three.JS零基础入门教程】第五篇:项目规划
     前期回顾:【Three.JS零基础入门教程】第一篇:搭建开发环境【Three.JS零基础入门教程】第二篇:起步案例【Three.JS零基础入门教程】第三篇:开发辅助【Three.JS零基础入门教程】第四篇:基础变换一个three.js的项目由这么几个部分组成场景物体灯光相机渲染器工具这里我们可以......
  • 【Nodejs】七、express中Router使用
    1、 什么是Routerexpress中的Router是一个完整的中间件和路由系统,可以看做是一个小型的app对象。2、Router作用对路由进行模块化,更好的管理路由3、Router使用创建独立的JS文件(homeRouter.js)//1.导入expressconstexpress=requi......
  • js实现翻牌游戏
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Document</title&g......
  • 关于JS里的字符表情乱码
    背景1、业务背景公司在处理业务时,需要使用socket传输字符串内容,在A处输入,在B处显示。但反馈说输入表情符号经过传输后,ios会变成问号,PC会乱码。如下情况:2、表情乱码表情符号乱码的原因通常与UTF-8编码的处理不当有关。表情符号属于Unicode中的高码点字符,需要使用4个字......
  • 基于nodejs+vue码头船只出行及配套货柜码放管理[程序+论文+开题]-计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着全球贸易的持续增长,港口作为连接国内外市场的重要枢纽,其运营效率与管理水平直接影响到物流链的顺畅与成本效益。码头作为港口的核心区域,船只的出行安排......
  • 基于nodejs+vue码上公益平台系统[程序+论文+开题]-计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,互联网已成为推动社会公益事业创新与发展的重要力量。传统公益模式在信息传播、资源调配、参与便捷性等方面面临诸多挑战,难以高效覆......
  • 基于nodejs+vue马寨工业园区招商管理系统[程序+论文+开题]-计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着全球经济一体化的深入发展,工业园区作为区域经济发展的重要载体,其招商引资工作日益成为推动地方经济增长的关键环节。马寨工业园区作为区域经济发展的重......
  • 基于nodejs+vue码上招聘云平台[程序+论文+开题]-计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景在数字化时代,互联网技术的飞速发展正深刻改变着各行各业,招聘行业也不例外。传统招聘模式受限于地域、时间、信息不对称等因素,导致企业难以快速精准地找到合......
  • JS中【回调函数】知识点讲解
    回调函数(CallbackFunction)是JavaScript中非常重要的概念,尤其是在处理异步操作时广泛使用。回调函数是一种通过参数传递的函数,在特定的操作或事件完成后,由另一个函数调用执行。基本概念函数作为参数:在JavaScript中,函数是一等公民,可以像变量一样传递给其他函数。当......
  • JS DOM 对象的节点操作
    目录一、什么是加载时间onload二、各种节点的获取方法1、元素节点的获取(1)通过标签名获取:       document.getElementsByTagName('标签名')(2)通过id获取         document.getElementById('id的名称')2、文本节点的获取举个栗子3、兄弟节点(1)nextSiblin......