0%

Vite 构建项目

Vite(法语意为 “快速的”,发音 /vit/发音同 “veet”)是一种新型前端构建工具,能够显著提升前端开发体验。它主要由两部分组成:

Vite 意在提供开箱即用的配置,同时它的 插件 APIJavaScript API 带来了高度的可扩展性,并有完整的类型支持。

运作方式

Vite 以 原生 ESM 方式提供源码。这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理。

  • Vite 将会使用 esbuild 预构建依赖。Esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍。

安装 & 启动

image-20220704092128035

  • 注意:Vite 需要 Node.js 版本 >= 12.0.0。

  • 不使用模板 【推荐】

1
2
3
4
5
6
#使用 NPM:  
npm init vite@latest
#yarn
yarn create vite
#pnpm 【推荐】
pnpm create vite
  • 填写项目名
  • 选择vue
  • 选择vue
  • 安装依赖包
  • 启动项目
1
2
3
4
5
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview"
},

vscode 插件推荐 Vue Language Features (Volar)

  • 首先保证vscode是最新版本!

  • 禁用 vetur插件(卸载vetur)

  • 安装

    • TypeScript Vue Plugin (Volar)
    • Vue Language Features

Vite.config.js配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
#path resolve方法获取本地绝对路径
import { resolve } from 'path'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
#别名处理
alias: {
'@': resolve(__dirname, 'src'), //别名 @相当于src 文件夹目录
//remove i18n waring
},
// why remove it , look for https://github.com/vitejs/vite/issues/6026
// extensions: ['.js', '.ts', '.jsx', '.tsx', '.json', '.vue', '.mjs']
},
//本地代理服务器 跨域处理
server: {
host: '0.0.0.0',
open: true,
proxy: {
// 前缀写法
'/api': {
target: 'http://localhost:5000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
//scss预处理
css: {
preprocessorOptions: {
scss: {
additionalData: "@import '@/assets/scss/_index.scss';",
},
},
},
})

安装sass

1
2
pnpm i sass -D
yarn add sass -D

入门开发

创建世界模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 创建场景
const scene = new three.Scene()
// 创建相机
const camera = new three.PerspectiveCamera(
45,//视角
window.innerWidth/window.innerHeight,//相机宽高比
0.1,//近平面
1000//远平面
)

// 创建渲染器
const render = new three.WebGLRenderer()
//设置渲染器尺寸大小
render.setSize(window.innerWidth,window.innerHeight)
// 渲染器添加到页面
document.body.appendChild(render.domElement)

// 创建几何体
const geometry = new three.BoxGeometry(1,1,1)
// 创建材质
const matetry = new three.MeshBasicMaterial({color:"red"})
// 创建网格:将物体与材质合起来
const cube = new three.Mesh(geometry,matetry)
// 将物体添加到场景中
scene.add(cube)

// 设置相机位置
camera.position.z = 5
camera.position.x = 5
camera.position.y = 5
camera.lookAt(0,0,0)

// 添加世界坐标辅助器
const axesHelper = new three.AxesHelper(5) //线条的长度
scene.add(axesHelper)


// 渲染函数
function animation(){
requestAnimationFrame(animation)
cube.rotation.x += 0.01
cube.rotation.y += 0.01
render.render(scene,camera)
}

animation()

轨道控制器

定义: Orbit controls(轨道控制器)可以使得相机围绕目标进行轨道运动。

1
2
3
4
5
6
7
//单独的库需要引进来
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'

// 添加轨道控制器:让相机围绕物体运动
const controls = new OrbitControls(camera,render.domElement)//此处需要设置为画布 不然设置body会阻塞body的其他事件
controls.enableDamping=true //设置带有阻尼惯性
controls.dampingFactor=0.01 //阻尼系数

前置知识

三维向量(Vector3)

该类表示的是一个三维向量(3D vector)。 一个三维向量表示的是一个有顺序的、三个为一组的数字组合(标记为x、y和z), 可被用来表示很多事物,例如:

  • 一个位于三维空间中的点。
  • 一个在三维空间中的方向与长度的定义。在three.js中,长度总是从(0, 0, 0)到(x, y, z)的 Euclidean distance(欧几里德距离,即直线距离), 方向也是从(0, 0, 0)到(x, y, z)的方向。
  • 任意的、有顺序的、三个为一组的数字组合。

其他的一些事物也可以使用二维向量进行表示,比如说动量矢量等等; 但以上这些是它在three.js中的常用用途。

构造函数 Vector3( x : Float, y : Float, z : Float )

x - 向量的x值,默认为0
y - 向量的y值,默认为0
z - 向量的z值,默认为0

欧拉角(Euler)

表示 Euler 的类。

欧拉角描述一个旋转变换,通过指定轴顺序和其各个轴向上的指定旋转角度来旋转一个物体。

构造器 Euler( x : Float, y : Float, z : Float, order : String )

x - (optional) 用弧度表示x轴旋转量。 默认值是 0
y - (optional) 用弧度表示y轴旋转量。 默认值是 0
z - (optional) 用弧度表示z轴旋转量。 默认值是 0
order - (optional) 表示旋转顺序的字符串,默认为’XYZ’(必须是大写)。

三维物体属性

position定义:表示对象的局部位置,有父元素根据父元素的位置进行移动,没得父元素则是根据世界坐标系来进行移动,是一个三维向量。 position.x/y/z 可单独设置某个坐标的位置。positon.set(三维坐标)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 创建几何体
const geometry = new three.BoxGeometry(1,1,1)
// 创建材质
const matetry = new three.MeshBasicMaterial({color:"red"})
const matetry1 = new three.MeshBasicMaterial({color:"green"})
// 创建网格:将物体与材质合起来
const parentCube = new three.Mesh(geometry,matetry1) //创建一个父类物体
const cube = new three.Mesh(geometry,matetry)
// 将子类添加到父类物体 此时子类的位移就是相对于父类物体了
parentCube.position.set(-3,0,0)
// 物体的位置
cube.position.set(3,0,0)

cube.scale.set(2,2,2)
parentCube.add(cube)
// 将物体添加到场景中
scene.add(parentCube)//呈现结果 父类盒子在x轴-3的到位置 子类盒子会在世界坐标系得远点上

scale定义:一个三维物体的局部缩放,有父级则相对于父级的尺寸进行缩放,没有父级则是默认值。也是一个三维向量。scale.set(三维坐标)

1
2
3
4
5
6
7
8
const parentCube = new three.Mesh(geometry,matetry1)  //创建一个父类物体 
const cube = new three.Mesh(geometry,matetry)
// 缩放:也视局部的缩放,有父级则相对于父级进行缩放,无父级则默认缩放
parentCube.scale.set(2,2,2)
cube.scale.set(2,2,2)
parentCube.add(cube)
// 将父类物体添加到场景中
scene.add(parentCube)

rotation定义: 物体的局部旋转,以弧度来表示。 如果有父级物体 他会收到父级物体的旋转,会在父级的基础上再进行旋转,反之则不会。rotation.x/y/z 或 rotation.set(三维坐标)

1
2
3
// 旋转:局部旋转 会受到父元素的旋转影响
parentCube.rotation.x = Math.PI/4
cube.rotation.x = Math.PI/4

屏幕自适应

监听window 视窗大小让画面实时变化

1
2
3
4
5
6
7
8
9
// 自适应屏幕大小
window.addEventListener('resize',()=>{
// 重新设置渲染器的宽高比
render.setSize(window.innerWidth,window.innerHeight)
// 重置相机的宽高比
camera.aspect= window.innerWidth / window.innerHeight
// 更新相机的投影矩阵
camera.updateProjectionMatrix()
})

全屏

1
2
3
4
5
6
7
8
9
10
11
12
13
// 开启全屏
const btn = document.createElement('button')
btn.innerHTML= '全屏'
btn.addEventListener('click',()=>{
// 要body进行全屏 而不是画布 不然按钮就看不见了
// render.domElement.requestFullscreen()
document.body.requestFullscreen()
})
btn.style.position = 'absolute'
btn.style.top = '20px'
btn.style.left = '20px'
btn.style.zIndex = '9999'
document.body.appendChild(btn)

空间节点Object3D

​ 使用情况:如果一个模块空间含有多个物体的情况,在其某个节点下添加子节点,此时缩放这个节点,它的所属空间也会跟着缩放,此时子节点的物体也会跟着缩放。避免这一情况的发生,我们会创建一个空的空间节点来来装这些空间,将节点与它的子节点装在其中,无需进行嵌套,因为此时这两个节点的远点都是相对空节点的原点。

材质(Material)和几何体(Geometry)可以被多个网格(Mesh)对象使用。比如在不同的位置画两个蓝色立方体,我们会需要两个网格(Mesh)对象来代表每一个立方体的位置和方向。但只需一个几何体(Geometry)来存放立方体的顶点数据,和一种材质(Material)来定义立方体的颜色为蓝色就可以了。两个网格(Mesh)对象都引用了相同的几何体(Geometry)和材质(Material)

材质:MeshBasicMaterial:不受光照影响, MeshPhongMaterial:受光照影响

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
const render1 = new three.WebGL1Renderer()
console.log(this.threeDom.style.width);
render1.setSize(w,h)
this.threeDom.appendChild(render1.domElement)
//设置相机的位置 与朝向
camere.position.set(0, 10, 0); //y轴距离10处
camere.up.set(0, 0, 1);//z轴在上
camere.lookAt(0, 0, 0);//看向原点
const arr = []
//设置一个球形缓存体的设置
const radius = 1
const widthSegmets = 360
const heightSegments = 360
//只在场景中进行添加
const sphereGemotry = new three.SphereGeometry(radius,widthSegmets,heightSegments)
//单独创建一个空余的空间来
const color = 0xffffff;
const intensity = 100;
const light = new three.PointLight(color, intensity);
light.position.set(-2,0,0)
scene.add(light);
//创建第一层空间 用于太阳 与含有嵌套关系的地月系统的第二层空间
const systemObje = new three.Object3D()
arr.push(systemObje)
const sunMaterial = new three.MeshPhongMaterial({emissive:0xffff00})
const sunMesh = new three.Mesh(sphereGemotry,sunMaterial)
sunMesh.scale.set(2,2,2)
systemObje.add(sunMesh)
arr.push(sunMesh)
//地月关系 创建第二层空间 其中含有嵌套关系
const other = new three.Object3D()
other.position.x = 10
arr.push(other)
systemObje.add(other)

const childMaterial = new three.MeshPhongMaterial({color: "#303438",emissive: "440fad"})
const childMseh = new three.Mesh(sphereGemotry,childMaterial)
childMseh.scale.set(1.5,1.5,1.5)
other.add(childMseh)
arr.push(childMseh)

const moonMaterial = new three.MeshPhongMaterial({color: "#303438",emissive: 0x112244})
const moonMesh = new three.Mesh(sphereGemotry,moonMaterial)
moonMesh.position.set(3,0,0)
arr.push(moonMesh)
other.add(moonMesh)

scene.add(systemObje)
const controls = new OrbitControls(camere, render1.domElement);
const axeHelper = new three.AxesHelper(50);
scene.add(axeHelper);
function animation() {
arr.forEach(item=>{
item.rotation.y += 0.01;
})

controls.update()
render1.render(scene, camere);
requestAnimationFrame(animation);
}
animation();