主頁 > 企業開發 > Three.js 進階之旅:新春特典-Rabbit craft go 🐇

Three.js 進階之旅:新春特典-Rabbit craft go 🐇

2023-01-23 06:53:03 企業開發

宣告:本文涉及圖文和模型素材僅用于個人學習、研究和欣賞,請勿二次修改、非法傳播、轉載、出版、商用、及進行其他獲利行為,

摘要

兔年到了,祝大家身體健,康萬事順利,本文內容作為兔年新春紀念頁面,將使用 Three.js 及 其他前端開發知識,創建一個以兔子為主題的 3D 簡單的趣味頁面 Rabbit craft go,本文內容包括使用純代碼創建三維浮島、小河、樹木、兔子、胡蘿卜以及兔子的運動互動、浮島的影片效果等,本文包含的知識點相對比較簡單,主要包括 使用 Three.js 網格立方體搭建三維卡通場景、鍵盤事件的監聽與三維場景影片的結合等,如果仔細閱讀并實踐過本專欄《Three.js 進階之旅》的話,非常容易掌握,

?? 兔子造型來源于 Three.js開源論壇,頁面整體造型靈感來源于《我的世界》,頁面名稱靈感來源于游戲《Lara Craft Go》,

效果

我們先來看看實作效果,頁面加載完成后是一個游戲操作提示界面,可以通過鍵盤 ? 空格鍵WASD 或方向鍵操作小兔子運動,點擊開始按鈕后,游戲提示界面消失,可以看到倒三角造型的天空浮島及浮島上方的樹木 ??、河流 ?、橋 ??、胡蘿卜 ??、兔子 ?? 等元素,接著攝像機鏡頭 ?? 自動拉近并聚焦到兔子上,

按照操作提示界面的按鍵,可以操作兔子進行前進、轉向、跳躍等運動,當兔子的運動位置觸碰到胡蘿卜時,胡蘿卜會消失同時兔子會進行跳躍運動,當兔子運動到小河或者超出浮島范圍時,兔子則會墜落到下方,

打開以下鏈接,在線預覽效果,大屏訪問效果更佳,

  • ????? 在線預覽地址:https://dragonir.github.io/rabbit-craft-go

本專欄系列代碼托管在 Github 倉庫【threejs-odessey】,后續所有目錄也都將在此倉庫中更新

?? 代碼倉庫地址:[email protected]:dragonir/threejs-odessey.git

實作

文章篇幅有限,因此刪減了三維模型的位置資訊等細節調整代碼,只提供構建三維模型的整體思路邏輯,想了解該部分內容的詳細介紹可以閱讀本專欄前幾篇文章及閱讀本文配套原始碼,現在,我們來看看整個頁面的實作詳細步驟:

頁面結構

Rabbit Craft Go 頁面的整體結構如下,其中 canvas.webgl 是用于渲染場景的容器、剩余標簽都是一些裝飾元素或提示語,

<canvas ></canvas>
<div  id="mask">
  <div >
    <div >
      <div ><span >W/↑</span></div>
      <div ><span >A/←</span><span >S/↓</span><span >D/→</span></div>
      <div ><span >space</span></div>
    </div>
    <p ><b>W</b>: 行走&emsp;<b>S</b>: 停止&emsp;<b>A</b>: 向左轉&emsp;<b>D</b>: 向右轉&emsp;<b>空格鍵</b>: 跳躍</p>
    <p ><button  id="start_button">開始</button></p>
  </div>
</div>
<a class='github' href='https://github.com/dragonir/threejs-odessey' target='_blank' rel='noreferrer'>
  <span class='author'>three.js odessey</span>
</a>
<h1 >RABBIT CRAFT GO!</h1>
<div ><i></i></div>

場景初始化

場景初始化程序中,我們引入必需的開發資源,并初始化渲染場景、相機、控制器、光照、頁面縮放適配等,其中外部資源的引入,其中 OrbitControls 用于頁面鏡頭縮放及移動控制;TWEENAnimations 用于生成鏡頭補間影片,也就是剛開始時浮島由遠及近的鏡頭切換影片中效果;IslandCarrotRabbitWaterfall 等是用來構建三維世界的類,為了使場景更加卡通化,使用了 THREE.sRGBEncoding 渲染效果,場景中添加了兩種光源,其中 THREE.DirectionalLight 用來生成陰影效果,

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { TWEEN } from "three/examples/jsm/libs/tween.module.min.js";
import Animations from './environment/animation';
import Island from './environment/island';
import Carrot from './environment/carrot';
import Rabbit from './environment/rabbit';
import Waterfall from './environment/waterfall';

// 初始化渲染器
const canvas = document.querySelector('canvas.webgl');
const renderer = new THREE.WebGLRenderer({
  canvas: canvas,
  antialias: true,
  alpha: true
});
renderer.setSize(sizes.width, sizes.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.shadowMap.enabled = true;
renderer.shadowMap.needsUpdate = true;

// 初始化場景
const scene = new THREE.Scene();

// 初始化相機
const camera = new THREE.PerspectiveCamera(60, sizes.width / sizes.height, 1, 5000)
camera.position.set(-2000, -250, 2000);

// 鏡頭控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.enableDamping = true;
controls.enablePan = false;
controls.dampingFactor = 0.15;

// 頁面縮放事件監聽
window.addEventListener('resize', () => {
  sizes.width = window.innerWidth;
  sizes.height = window.innerHeight;
  // 更新渲染
  renderer.setSize(sizes.width, sizes.height);
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
  // 更新相機
  camera.aspect = sizes.width / sizes.height;
  camera.updateProjectionMatrix();
});

// 光照
const ambientLight = new THREE.AmbientLight(0xffffff, 1);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
scene.add(directionalLight);

創建浮島

如以下 ?? 兩幅圖所示,整個浮島造型是一個四棱椎,整體分為四部分,頂部是由地面和河流構成的四方體、底部三塊是倒置的三角,生成這些三維模型的其實也并沒有多少技巧,就像搭積木一樣使用 Three.js 提供的立方體網格通過計算拼接到一起即可,類 Island 包含一個方法 generate 用于創建上述三維模型,并將所創建模型添加到三維分組 floorMesh 中用于外部呼叫,其中棱柱部分是通過 CylinderBufferGeometry 來實作的,

export default class Island {
  constructor() {
    this.floorMesh = new THREE.Group();
    this.generate();
  }

  generate() {
    // 左側地面
    const leftFieldMat = new THREE.MeshToonMaterial({
      color: 0x015521d,
      side: THREE.DoubleSide,
    });
    const leftFieldGeom = new THREE.BoxBufferGeometry(800, 30, 1800);
    this.leftFieldMesh = new THREE.Mesh(leftFieldGeom, leftFieldMat);
    // 右側地面
    this.rightFieldMesh = this.leftFieldMesh.clone();
    const mapCapMat = new THREE.MeshMatcapMaterial({
      matcap: new THREE.TextureLoader().load('./images/matcap.png'),
      side: THREE.DoubleSide
    })
    // 頂部棱柱
    const topFieldGeom = new THREE.CylinderBufferGeometry(1200, 900, 200, 4, 4);
    this.topFieldMesh = new THREE.Mesh(topFieldGeom, mapCapMat);
    // 中間棱柱
    const middleFieldGeom = new THREE.CylinderBufferGeometry(850, 600, 200, 4, 4);
    this.middleFieldMesh = new THREE.Mesh(middleFieldGeom, mapCapMat);
    // 底部棱錐
    const bottomFieldGeom = new THREE.ConeBufferGeometry(550, 400, 4);
    this.bottomFieldMesh = new THREE.Mesh(bottomFieldGeom, mapCapMat);
    // 河面
    const strGroundMat = new THREE.MeshLambertMaterial({
      color: 0x75bd2d,
      side: THREE.DoubleSide,
    });
    const strCroundGeom = new THREE.BoxBufferGeometry(205, 10, 1800);
    this.strGroundMesh = new THREE.Mesh(strCroundGeom, strGroundMat);

    // 小河
    const streamMat = new THREE.MeshLambertMaterial({
      color: 0x0941ba,
      side: THREE.DoubleSide,
    });
    const streamGeom = new THREE.BoxBufferGeometry(200, 16, 1800);
    this.streamMesh = new THREE.Mesh(streamGeom, streamMat);
    // ...
  }
};

浮島俯視圖是一個正方形

浮島側視圖是一個倒三角形

創建水流

接下來,我們為河流添加一個小瀑布,使場景動起來,流動的瀑布三維水滴 ?? 滴落效果的是通過創建多個限定范圍內隨機位置的 THREE.BoxBufferGeometry 來實作水滴模型,然后通過水滴的顯示隱藏影片實作視覺上的水滴墜落效果,Waterfall 類用于創建單個水滴,它為水滴初始化隨機位置和速度,并提供一個 update 方法用來更新它們,

export default class Waterfall {
  constructor (scene) {
    this.scene = scene;
    this.drop = null;
    this.generate();
  }
  generate () {
    this.geometry = new THREE.BoxBufferGeometry(15, 50, 5);
    this.material = new THREE.MeshLambertMaterial({ color: 0x0941ba });
    this.drop = new THREE.Mesh(this.geometry, this.material);
    this.drop.position.set((Math.random() - 0.5) * 200, -50, 900 + Math.random(1, 50) * 10);
    this.scene.add(this.drop);
    this.speed = 0;
    this.lifespan = Math.random() * 50 + 50;
    this.update = function() {
      this.speed += 0.07;
      this.lifespan--;
      this.drop.position.x += (5 - this.drop.position.x) / 70;
      this.drop.position.y -= this.speed;
    };
  }
};

完成水滴創建后,不要忘了需要在頁面重繪影片 tick 方法中像這樣更新已創建的水滴陣列 drops,使其看起來生成向下流動墜落的效果,

for (var i = 0; i < drops.length; i++) {
  drops[i].update();
  if (drops[i].lifespan < 0) {
    scene.remove(scene.getObjectById(drops[i].drop.id));
    drops.splice(i, 1);
  }
}

創建橋

在河流上方添加一個小木橋 ??,這樣小兔子就可以通過木橋在小河兩邊移動了, 類 Bridge 通過 generate 方法創建一個小木橋,并通過三維模型組 bridgeMesh 將其匯出,我們可以在上面創建的 Island 類中使用它,將其添加到三維場景中,

export default class Bridge {
  constructor() {
    this.bridgeMesh = new THREE.Group();
    this.generate();
  }
  generate() {
    var woodMat = new THREE.MeshLambertMaterial({
      color: 0x543b14,
      side: THREE.DoubleSide
    });
    // 木頭
    for (var i = 0; i < 15; i++) {
      var blockGeom = new THREE.BoxBufferGeometry(10, 3, 70);
      var block = new THREE.Mesh(blockGeom, woodMat);
      this.bridgeMesh.add(block);
    }
    // 橋尾
    var geometry_rail_v = new THREE.BoxBufferGeometry(3, 20, 3);
    var rail_1 = new THREE.Mesh(geometry_rail_v, woodMat);
    var rail_2 = new THREE.Mesh(geometry_rail_v, woodMat);
    var rail_3 = new THREE.Mesh(geometry_rail_v, woodMat);
    var rail_4 = new THREE.Mesh(geometry_rail_v, woodMat);
    // ...
  }
}

創建樹

從預覽動圖和頁面可以看到,浮島上共有兩種樹 ??,綠色的高樹和粉紅色的矮樹,樹的實作也非常簡單,是使用了兩個 BoxBufferGeometry 拼接到一起,類 TreeLeafTree 分別用于生成這兩種樹木,接收引數 (x, y, z) 分別表示樹木在場景中的位置資訊,我們可以在 Island 輔導上添加一些樹木,構成浮島上的一片小森林,

export default class Tree {
  constructor(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
    this.treeMesh = new THREE.Group();
    this.generate();
  }
  generate() {
    // 樹干
    var trunkMat = new THREE.MeshLambertMaterial({
      color: 0x543b14,
      side: THREE.DoubleSide
    });
    var trunkGeom = new THREE.BoxBufferGeometry(20, 200, 20);
    this.trunkMesh = new THREE.Mesh(trunkGeom, trunkMat);
    // 樹葉
    var leavesMat = new THREE.MeshLambertMaterial({
      color: 0x016316,
      side: THREE.DoubleSide
    });
    var leavesGeom = new THREE.BoxBufferGeometry(80, 400, 80);
    this.leavesMesh = new THREE.Mesh(leavesGeom, leavesMat);
    this.treeMesh.add(this.trunkMesh);
    this.treeMesh.add(this.leavesMesh);
    this.treeMesh.position.set(this.x, this.y, this.z);
    // ...
  }
}

矮樹

export default class LeafTree {
  constructor(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
    this.treeMesh = new THREE.Group();
    this.generate();
  }
  generate() {
    // ...
  }
}

創建胡蘿卜

接著,在地面上添加一些胡蘿卜 ??,胡蘿卜身體部分是通過四棱柱 CylinderBufferGeometry 實作的,然后通過 BoxBufferGeometry 立方體來實作胡蘿卜的兩片葉子,場景中可以通過 Carrot 類來添加胡蘿卜,本頁面示例中是通過回圈呼叫添加了 20 個隨機位置的胡蘿卜,

export default class Carrot {
  constructor() {
    this.carrotMesh = new THREE.Group();
    this.generate();
  }
  generate() {
    const carrotMat = new THREE.MeshLambertMaterial({
      color: 0xd9721e
    });
    const leafMat = new THREE.MeshLambertMaterial({
      color: 0x339e33
    });
    // 身體
    const bodyGeom = new THREE.CylinderBufferGeometry(5, 3, 12, 4, 1);
    this.body = new THREE.Mesh(bodyGeom, carrotMat);
    // 葉子
    const leafGeom = new THREE.BoxBufferGeometry(5, 10, 1, 1);
    this.leaf1 = new THREE.Mesh(leafGeom, leafMat);
    this.leaf2 = this.leaf1.clone();
    // ...
    this.carrotMesh.add(this.body);
    this.carrotMesh.add(this.leaf1);
    this.carrotMesh.add(this.leaf2);
  }
};
for (let i = 0; i < 20; i++) {
  carrot[i] = new Carrot();
  scene.add(carrot[i].carrotMesh);
  carrot[i].carrotMesh.position.set(-170 * Math.random() * 3 - 300, -12, 1400 * Math.random() * 1.2 - 900);
}

創建兔子

最后,來創建頁面的主角兔子 ??,兔子全部都是由立方體 BoxBufferGeometry 搭建而成的,整體可以分解為頭、眼睛、耳朵、鼻子、嘴、胡須、身體、尾巴、四肢等構成,構建兔子時的核心要素就是各個立方體位置和縮放比例的調整,需要具備一定的審美能力,當然本例中使用的兔子是在 Three.js 社區開源代碼的基礎上改造的 ??

完成兔子的整體外形之后,我們通過 gsap 給兔子添加一些運動影片效果和方法以供外部呼叫,其中 blink() 方法用于眨眼、jump() 方法用于原地跳躍、nod() 方法用于點頭、run() 方法用于奔跑、fall() 方法用于邊界檢測時檢測到超出運動范圍時使兔子墜落效果等,完成 Rabbit 類后,我們就可以在場景中初始化小兔子,

import { TweenMax, Power0, Power1, Power4, Elastic, Back } from 'gsap';

export default class Rabbit {
  constructor() {
    this.bodyInitPositions = [];
    this.runningCycle = 0;
    this.rabbitMesh = new THREE.Group();
    this.bodyMesh = new THREE.Group();
    this.headMesh = new THREE.Group();
    this.generate();
  }
  generate() {
    var bodyMat = new THREE.MeshLambertMaterial({
      color: 0x5c6363
    });
    var tailMat = new THREE.MeshLambertMaterial({
      color: 0xc2bebe
    });
    var nouseMat = new THREE.MeshLambertMaterial({
      color: 0xed716d
    });
    // ...
    var pawMat = new THREE.MeshLambertMaterial({
      color: 0xbf6970
    });
    var bodyGeom = new THREE.BoxBufferGeometry(50, 50, 42, 1);
    var headGeom = new THREE.BoxBufferGeometry(44, 44, 54, 1);
    var earGeom = new THREE.BoxBufferGeometry(5, 60, 10, 1);
    var eyeGeom = new THREE.BoxBufferGeometry(20, 20, 8, 1);
    var irisGeom = new THREE.BoxBufferGeometry(8, 8, 8, 1);
    var mouthGeom = new THREE.BoxBufferGeometry(8, 16, 4, 1);
    var mustacheGeom = new THREE.BoxBufferGeometry(0.5, 1, 22, 1);
    var spotGeom = new THREE.BoxBufferGeometry(1, 1, 1, 1);
    var legGeom = new THREE.BoxBufferGeometry(33, 33, 10, 1);
    var pawGeom = new THREE.BoxBufferGeometry(45, 10, 10, 1);
    var pawFGeom = new THREE.BoxBufferGeometry(20, 20, 20, 1);
    var tailGeom = new THREE.BoxBufferGeometry(20, 20, 20, 1);
    var nouseGeom = new THREE.BoxBufferGeometry(20, 20, 15, 1);
    var tailGeom = new THREE.BoxBufferGeometry(23, 23, 23, 1);
    this.body = new THREE.Mesh(bodyGeom, bodyMat);
    this.bodyMesh.add(this.body);
    this.head = new THREE.Mesh(headGeom, bodyMat);
    this.bodyMesh.add(this.legL);
    this.headMesh.add(this.earR);
    this.rabbitMesh.add(this.bodyMesh);
    this.rabbitMesh.add(this.headMesh);
    // ...
  }
  blink() {
    var sp = 0.5 + Math.random();
    if (Math.random() > 0.2)
      TweenMax.to([this.eyeR.scale, this.eyeL.scale], sp / 8, {
        y: 0,
        ease: Power1.easeInOut,
        yoyo: true,
        repeat: 3
      });
  }
  // 跳躍
  jump() {
    var speed = 10;
    var totalSpeed = 10 / speed;
    var jumpHeight = 150;
    TweenMax.to(this.earL.rotation, totalSpeed / 2, {
      z: "+=.3",
      ease: Back.easeOut,
      yoyo: true,
      repeat: 1
    });
    TweenMax.to(this.earR.rotation, totalSpeed / 2, {
      z: "-=.3",
      ease: Back.easeOut,
      yoyo: true,
      repeat: 1
    });
    // ...
  }
  // 點頭
  nod() {}
  // 奔跑
  run() {}
  // 移動
  move() {}
  // 墜落
  fall() {}
  // 動作銷毀
  killNod() {}
  killJump() {}
  killMove() {}
}

將兔子添加到場景中,

添加影片和操作

為了使兔子可以運動和可互動,我們通過監聽鍵盤按鍵的方式來呼叫兔子類內置的對應影片方法,兔子的方向轉動可以通過修改兔子的旋轉屬性 rotation 來實作,

// 兔子控制
const rabbitControl = {
  tureLeft: () => {
    rabbit && (rabbit.rabbitMesh.rotation.y -= Math.PI / 2);
  },
  turnRight: () => {
    rabbit && (rabbit.rabbitMesh.rotation.y += Math.PI / 2);
  },
  stopMove: () => {
    rabbitMoving = false;
    rabbit.killMove();
    rabbit.nod();
  },
}

// 鍵盤監聽
document.addEventListener('keydown', e => {
  if (e && e.keyCode) {
    switch(e.keyCode) {
      // 左
      case 65:
      case 37:
        rabbitControl.tureLeft();
        break;
      // 右
      case 68:
      case 39:
        rabbitControl.turnRight();
        break;
      // 前
      case 87:
      case 38:
        rabbitMoving = true;
        break;
      // 空格鍵
      case 32:
        !rabbitJumping && rabbit.jump() && (rabbitJumping = true);
        break;
      default:
        break;
    }
  }
});

document.addEventListener('keyup', e => {
  if (e && e.keyCode) {
    switch(e.keyCode) {
      case 83:
      case 40:
      case 87:
      case 38:
        rabbitMoving = false;
        rabbit.killMove();
        rabbit.nod();
        break;
      case 32:
        setTimeout(() => {
          rabbitJumping = false;
        }, 800);
        break;
    }
  }
});

為了使場景更加真實和趣味,我們可以添加一些邊界檢測方法,當兔子位置處于非可運動區域如小河、浮島之外等區域時,可以呼叫兔子的 fall(),方法使其墜落,當檢測到兔子的位置和胡蘿卜的位置重疊時,給兔子添加了一個 jump() 跳躍動作并使檢測到的這個胡蘿卜從場景中移除,

const checkCollision = () => {
  for (let i = 0; i < 20; i++) {
    let rabbCarr = rabbit.rabbitMesh.position.clone().sub(carrot[i].carrotMesh.position.clone());
    if (rabbCarr.length() <= 20) {
      rabbit.jump();
      scene.remove(carrot[i].carrotMesh);
      rabbCarr = null;
    }
  }
  // 檢查是否是地面的邊界
  var rabbFloor = island.floorMesh.position.clone().sub(rabbit.rabbitMesh.position.clone());
  if (
    rabbFloor.x <= -900 ||
    rabbFloor.x >= 900 ||
    rabbFloor.z <= -900 ||
    rabbFloor.z >= 900
  ) {
    rabbit.fall();
  }
  // 小河檢測
  var rabbStream = rabbit.rabbitMesh.position.clone().sub(island.streamMesh.position.clone());
  if (
    (rabbStream.x >= -97 &&
      rabbStream.x <= 97 &&
      rabbStream.z >= -900 &&
      rabbStream.z <= 688) ||
    (rabbStream.x >= -97 && rabbStream.x <= 97 && rabbStream.z >= 712)
  ) {
    rabbit.fall();
  }
}

頁面裝飾

最后,我們來制作一個其實頁面,中間部分是鍵盤操作說明,底部是一些裝飾文案圖片,操作提示下方是一個開始按鈕,我們給這個按鈕添加一個通過 TWEEN.js 實作的鏡頭補間影片效果,當點擊按鈕時,頁面首先顯示的是倒置三角造型的浮島,然后鏡頭慢慢方法拉近,顯示出兔子運動的區域,本頁面為了使其看起來更加符合游戲主題,標題文案使用了一種像素化的字體 ?

const startButton = document.getElementById('start_button');
const mask = document.getElementById('mask');
startButton.addEventListener('click', () => {
  mask.style.display = 'none';
  Animations.animateCamera(camera, controls, { x: 50, y: 120, z: 1000 }, { x: 0, y: 0, z: 0 }, 3600, () => {});
});

?? 原始碼地址:https://github.com/dragonir/threejs-odessey

總結

本文中主要包含的知識點包括:

  • 使用 Three.js 網格立方體搭建三維卡通場景
  • 鍵盤事件的監聽與三維場景影片的結合

想了解其他前端知識或其他未在本文中詳細描述的Web 3D開發技術相關知識,可閱讀我往期的文章,如果有疑問可以在評論中留言,如果覺得文章對你有幫助,不要忘了一鍵三連哦 ??

附錄

  • [1]. ?? Three.js 打造繽紛夏日3D夢中情島
  • [2]. ?? Three.js 實作炫酷的賽博朋克風格3D數字地球大屏
  • [3]. ?? Three.js 實作2022冬奧主題3D趣味頁面,含冰墩墩
  • [4]. ?? Three.js 實作3D開放世界小游戲:阿貍的多元宇宙
  • [5]. ?? 1000粉!使用Three.js實作一個創意紀念頁面
  • ...
  • 【Three.js 進階之旅】系列專欄訪問 ??
  • 更多往期【3D】專欄訪問 ??
  • 更多往期【前端】專欄訪問 ??

參考

  • [1]. three.js journey
  • [2]. threejs.org

本文作者:dragonir 本文地址:https://www.cnblogs.com/dragonir/p/17064580.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/542354.html

標籤:其他

上一篇:JavaScript 記憶體管理及垃圾回收

下一篇:JavaScript 實作繼承

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more