(一) Three.js And TypeScript

1. 概述

本文主要介紹以下三個(gè)部分:

  • 配置開發(fā)環(huán)境(vs code, git and nodejs)
  • TypeScript快速入門
  • 初始化Three.js項(xiàng)目工程

本文代碼倉(cāng)庫(kù)地址:https://github.com/ue007/three.ts

2. 配置開發(fā)環(huán)境

3. TypeScript快速入門

代碼地址:https://github.com/ue007/three.ts/tree/main/01-HelloTypeScript

3.1 TypeScript介紹

TypeScript 是 JavaScript 的一個(gè)超集,支持 ECMAScript 6 標(biāo)準(zhǔn)(ES6 教程)皮假。

TypeScript 由微軟開發(fā)的自由和開源的編程語言稽坤。

TypeScript 設(shè)計(jì)目標(biāo)是開發(fā)大型應(yīng)用,它可以編譯成純 JavaScript闰蚕,編譯出來的 JavaScript 可以運(yùn)行在任何瀏覽器上。

3.1.1 JavaScript 與 TypeScript 的區(qū)別

TypeScript 是 JavaScript 的超集,擴(kuò)展了 JavaScript 的語法卖怜,因此現(xiàn)有的 JavaScript 代碼可與 TypeScript 一起工作無需任何修改键思,TypeScript 通過類型注解提供編譯時(shí)的靜態(tài)類型檢查础爬。

TypeScript 可處理已有的 JavaScript 代碼,并只對(duì)其中的 TypeScript 代碼進(jìn)行編譯吼鳞。

[圖片上傳失敗...(image-45c071-1618983989118)]

[圖片上傳失敗...(image-2d3302-1618983989118)]

3.1.2 為什么選擇TypeScript?

開發(fā)者選擇使用TypeScript語言至少有以下幾點(diǎn)原因:

能夠更早地發(fā)現(xiàn)代碼中的錯(cuò)誤看蚜。
能夠幫助提高生產(chǎn)力。
支持JavaScript語言的最新特性并且使用了與JavaScript語言相同的語法和語義赔桌。

3.2 安裝TypeScript

打開終端供炎,全局安裝typescript:

npm install -g typescript

查看typescript版本

tsc -v

3.3 創(chuàng)建foo.js文件

代碼地址:https://github.com/ue007/three.ts/01-HelloThree

創(chuàng)建foo.js文件,并輸入代碼:

function foo(bar) {
    return "Hello, " + bar;
}

let baz = "ThreeJs With TypeScript";

console.log(foo(baz));

直接在Node環(huán)境下執(zhí)行疾党,在控制臺(tái)輸入:

node foo.js

輸出內(nèi)容:

Hello, ThreeJs With TypeScript

3.4 創(chuàng)建foo.ts文件

下面使用ts方式音诫,等效輸出foo.js文件。

[圖片上傳失敗...(image-d9e811-1618983989118)]

首先雪位,將foo.js文件重命名為foo.ts竭钝。

其次,在控制臺(tái)雹洗,輸入如下命令:

tsc foo.ts

編譯完成之后香罐,會(huì)對(duì)應(yīng)生成foo.js文件,并在node環(huán)境下執(zhí)行命令:

node foo.js

同樣輸出如下結(jié)果:

Hello, ThreeJs With TypeScript

3.5 Interfaces介紹

在TypeScript中时肿,接口(Interfaces)和類型聲明(Type Declarations)提供了幾乎完全相同的功能庇茫。接口/類型是用于類型檢查的結(jié)構(gòu)。接口/類型定義了對(duì)象可以擁有的屬性和類型螃成。

替換foo.ts文件中代碼如下:

interface Quux {
  quuz: string;
  corge: number;
}

function foo(bar: Quux) {
  return 'Hello, ' + bar.quuz + ' ' + bar.corge;
}

let baz: Quux = {
  quuz: 'ABC',
  corge: 123,
};

console.log(foo(baz));
 

執(zhí)行命令:

tsc foo.ts
node foo.js

在Node環(huán)境中執(zhí)行結(jié)果:

Hello, ABC 123

3.6 Classes介紹

類(Classes)旦签,本質(zhì)上是對(duì)象在實(shí)現(xiàn)時(shí)應(yīng)該是什么樣的藍(lán)圖啥容。一個(gè)類可以有初始化的屬性和方法來幫助創(chuàng)建和修改對(duì)象。

定義一個(gè)Grault類顷霹,代碼如下:

class Grault {
  private garply: string;

  constructor(quux: Quux, waldo: number[]) {
    this.garply = quux.quuz + ' ' + quux.corge + ' ' + waldo;
  }

  public getGarply() {
    return this.garply;
  }
}

interface Quux {
  quuz: string;
  corge: number;
}

let baz = { quuz: 'ABC', corge: 123 };

let fred: Grault = new Grault(baz, [1, 2, 3]);

console.log(fred.getGarply());

執(zhí)行命令:

tsc foo.ts
node foo.js

在Node環(huán)境中執(zhí)行結(jié)果:

ABC 123 1,2,3

3.7 在瀏覽器中運(yùn)行

創(chuàng)建foo.html文件咪惠,并寫入如下代碼:

<!DOCTYPE html>
<html>

<head>
    <title>TypeScript Crash Course</title>
</head>

<body>
    <script src="foo.js"></script>
</body>

</html>

在foo.ts文件中添加如下代碼:

class Grault {
  private garply: string;

  constructor(quux: Quux, waldo: number[]) {
    this.garply = quux.quuz + ' ' + quux.corge + ' ' + waldo;
  }

  public getGarply() {
    return this.garply;
  }
}

interface Quux {
  quuz: string;
  corge: number;
}

let baz = { quuz: 'ABC', corge: 123 };

let fred: Grault = new Grault(baz, [1, 2, 3]);

console.log(fred.getGarply());

try {
  document.body.innerHTML = fred.getGarply();
} catch (e) {}

使用vscode編輯器打開Live Server服務(wù)器,在瀏覽器中查看foo.html頁面淋淀,效果如下:

[圖片上傳失敗...(image-a27854-1618983989118)]

4. 初始化Three.js項(xiàng)目

接下來遥昧,我們將創(chuàng)建Three.js項(xiàng)目模板。代碼地址:https://github.com/ue007/three.ts/tree/main/02-HelloThreeTS

4.1 創(chuàng)建工程目錄

mkdir 02-HelloThreeTS

4.2 初始化工程

使用npm進(jìn)行初始化

npm init

一直回車朵纷,直至初始化完成炭臭,在目錄下會(huì)生成package.json文件。

4.3 安裝Three.js依賴庫(kù)

執(zhí)行命令:

cnpm install @types/three --save-dev // 具有類型生命的three版本

4.4 創(chuàng)建目錄結(jié)構(gòu)

按照如下目錄結(jié)構(gòu)袍辞,創(chuàng)建文件和目錄:

|-- Three.js-TypeScript-Tutorial
    |-- dist
        |-- client
            |-- index.html
        |-- server
    |-- node_modules
        |-- three
            |-- (Several extra files and folders containing the Three.js source code)
    |-- src
        |-- client
        |-- server
    |-- package.json
    |-- package-lock.json

其中dist/client/index.html文件內(nèi)容如下:

<!DOCTYPE html>
<html>

<head>
    <title>Three.js TypeScript Tutorials</title>
</head>

<body>
    <script type="module" src="client.js"></script>
</body>

</html>

4.5 添加初始化代碼

4.5.1 client.ts

在src/client.ts文件中鞋仍,添加如下代碼:

const scene: THREE.Scene = new THREE.Scene();

const camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);

const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const geometry: THREE.BoxGeometry = new THREE.BoxGeometry();
const material: THREE.MeshBasicMaterial = new THREE.MeshBasicMaterial({
  color: 0x00ff00,
  wireframe: true,
});

const cube: THREE.Mesh = new THREE.Mesh(geometry, material);
scene.add(cube);

camera.position.z = 2;

var animate = function () {
  requestAnimationFrame(animate);

  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;

  renderer.render(scene, camera);
};

animate();

在src/client文件夾中,創(chuàng)建tsconfig.json文件搅吁,并插入如下代碼:

{
    "compilerOptions": {
        "target": "ES6",
        "module": "ES6",
        "outDir": "../../dist/client",
        "moduleResolution": "node"
    },
    "include": [
        "**/*.ts"
    ]
}

4.5.2 server.ts

在src/server目錄下威创,創(chuàng)建server.ts文件,并插入如下代碼:

const port: number = 3000

class App {
    private server: http.Server
    private port: number

    constructor(port: number) {
        this.port = port
        const app = express()
        app.use(express.static(path.join(__dirname, '../client')))

        this.server = new http.Server(app);
    }

    public Start() {
        this.server.listen(this.port, () => {
            console.log( `Server listening on port ${this.port}.` )
        })
    }
}

new App(port).Start()

在src/server文件夾中谎懦,創(chuàng)建tsconfig.json文件肚豺,并插入如下代碼:

{
    "compilerOptions": {
        "target": "ES2019",
        "module": "commonjs",
        "outDir": "../../dist/server",
        "sourceMap": true,
        "esModuleInterop": true
    },
    "include": [
        "**/*.ts"
    ]
}

4.5.3 目錄結(jié)構(gòu)

創(chuàng)建完成之后的目錄結(jié)構(gòu)如下:

|-- Three.js-TypeScript-Tutorial
    |-- dist
        |-- client
            |-- index.html
        |-- server
    |-- node_modules
        |-- three
            |-- (Several extra files and folders containing the Three.js source code)
    |-- src
        |-- client
            |-- client.ts
            |-- tsconfig.json
        |-- server
            |-- server.ts
            |-- tsconfig.json
    |-- package.json
    |-- package-lock.json

4.6 引入依賴

上面代碼,我們會(huì)發(fā)現(xiàn)界拦,在編輯器中會(huì)提示錯(cuò)誤吸申,如不能找到對(duì)應(yīng)的namespace等等,這是因?yàn)檫€沒有引入對(duì)應(yīng)的依賴享甸。

4.6.1 client side

創(chuàng)建client.ts文件截碴,代碼如下:

import * as THREE from '/build/three.module.js'
import { OrbitControls } from '/jsm/controls/OrbitControls'

const scene: THREE.Scene = new THREE.Scene()

const camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)

const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)

const controls = new OrbitControls(camera, renderer.domElement)

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

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

camera.position.z = 2

var animate = function () {

    requestAnimationFrame(animate)

    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;

    controls.update()

    renderer.render(scene, camera)

}; 

animate(); 

創(chuàng)建tsconfig.json文件,代碼如下:

{
    "compilerOptions": {
        "target": "ES6",
        "module": "ES6",
        "outDir": "../../dist/client",
        "baseUrl": ".",
        "paths": {
            "/build/three.module.js": ["../../node_modules/@types/three"],
            "/jsm/*": ["../../node_modules/@types/three/examples/jsm/*"],
        },
        "moduleResolution": "node"
    },
    "include": [
        "**/*.ts"
    ]
}

執(zhí)行編譯腳本:

tsc -p .\src\client\

4.6.2 server side

在server.ts文件開頭蛉威,引入如下代碼:

import express from "express"
import path from "path"
import http from "http"

安裝依賴:

cnpm install @types/node --save-dev
cnpm install @types/express --save-dev
cnpm install express --save-dev

完整代碼如下:

import express from "express"
import path from "path"
import http from "http"

const port: number = 3000

class App {
    private server: http.Server
    private port: number

    constructor(port: number) {
        this.port = port
        const app = express()
        app.use(express.static(path.join(__dirname, '../client')))
        app.use('/build/three.module.js', express.static(path.join(__dirname, '../../node_modules/three/build/three.module.js')))
        app.use('/jsm/controls/OrbitControls', express.static(path.join(__dirname, '../../node_modules/three/examples/jsm/controls/OrbitControls.js')))

        this.server = new http.Server(app);
    }

    public Start() {
        this.server.listen(this.port, () => {
            console.log( `Server listening on port ${this.port}.` )
        })
    }
}

new App(port).Start()

編譯server.ts文件日丹,命令如下:

tsc -p ./src/server

對(duì)應(yīng)會(huì)在dist/server目錄下,生成server.js文件和server.js.map文件瓷翻。

執(zhí)行腳本聚凹,啟動(dòng)服務(wù)器:

node .\dist\server\server.js 

在瀏覽器中割坠,打開地址:localhost:3000

img

4.7 配置TSC Watch

繼續(xù)配置項(xiàng)目齐帚,使得源代碼在發(fā)生任何更改的時(shí)候,重新編譯彼哼, 添加-w表示watch狀態(tài)对妄。

tsc -p src/server/ -w 

4.8 配置Nodemon

nodemon nodemon是一種工具,可以自動(dòng)檢測(cè)到目錄中的文件更改時(shí)通過重新啟動(dòng)應(yīng)用程序來調(diào)試基于node.js的應(yīng)用程序。

安裝nodemon:

npm install --save-dev nodemon

啟動(dòng)服務(wù):

npx nodemon dist/server/server.js

4.9 一鍵啟動(dòng)

我們可以創(chuàng)建一個(gè)命令來同時(shí)啟動(dòng)兩個(gè)進(jìn)程敢朱,而不是一直輸入這些compile和nodemon命令剪菱。

安裝concurrently:

npm install --save-dev concurrently

在package.json文件中添加腳本:

"dev" : "concurrently -k \"tsc -p ./src/server -w\" \"nodemon ./dist/server/server.js\"",

執(zhí)行命令:

npm run dev

打開瀏覽器摩瞎,輸入地址:localhost:3000,效果如下:

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末孝常,一起剝皮案震驚了整個(gè)濱河市旗们,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌构灸,老刑警劉巖上渴,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異喜颁,居然都是意外死亡稠氮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門半开,熙熙樓的掌柜王于貴愁眉苦臉地迎上來隔披,“玉大人,你說我怎么就攤上這事寂拆∩菝祝” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵纠永,是天一觀的道長(zhǎng)恃慧。 經(jīng)常有香客問我,道長(zhǎng)渺蒿,這世上最難降的妖魔是什么痢士? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮茂装,結(jié)果婚禮上怠蹂,老公的妹妹穿的比我還像新娘。我一直安慰自己少态,他們只是感情好城侧,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著彼妻,像睡著了一般嫌佑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上侨歉,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天屋摇,我揣著相機(jī)與錄音,去河邊找鬼幽邓。 笑死炮温,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的牵舵。 我是一名探鬼主播柒啤,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼倦挂,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了担巩?” 一聲冷哼從身側(cè)響起方援,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎涛癌,沒想到半個(gè)月后肯骇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡祖很,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年笛丙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片假颇。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡胚鸯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出笨鸡,到底是詐尸還是另有隱情姜钳,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布形耗,位于F島的核電站哥桥,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏激涤。R本人自食惡果不足惜拟糕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望倦踢。 院中可真熱鬧送滞,春花似錦、人聲如沸辱挥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽晤碘。三九已至褂微,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間园爷,已是汗流浹背宠蚂。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留腮介,地道東北人肥矢。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像叠洗,于是被迫代替她去往敵國(guó)和親甘改。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 當(dāng)使用第三方庫(kù)時(shí)灭抑,我們需要引用它的聲明文件十艾,才能獲得對(duì)應(yīng)的代碼補(bǔ)全、接口提示等功能腾节。這是因?yàn)榍岸说谌綆?kù)大多都是非...
    CondorHero閱讀 4,871評(píng)論 1 5
  • THREE.js 是javascript的一個(gè)三維庫(kù)忘嫉,Github網(wǎng)址https://github.com/mrd...
    圣_狒司機(jī)閱讀 2,138評(píng)論 0 1
  • 1. HTML 1. 必考:你是如何理解 HTML 語義化的? 荒野階段:最開始是 PHP 后端寫 HTML案腺,不會(huì)...
    Qingelin閱讀 695評(píng)論 0 0
  • Three.js是一個(gè)偉大的開源WebGL庫(kù)庆冕,WebGL允許JavaScript操作GPU,在瀏覽器端實(shí)現(xiàn)真正意義...
    無言以越閱讀 2,950評(píng)論 3 19
  • 這一章主要總結(jié)TypeScript的用法和項(xiàng)目常用配置 編譯上下文 用來給文件分組劈榨,告訴 TypeScript 哪...
    Terryzh閱讀 1,999評(píng)論 0 0