使用vue+vite+ts+vitest创建canvas图形项目
前言
学习目标
- 快速创建vue+vite+ts+vitest 项目
- 搭建测试环境
知识点
- vue
- vite
- ts
- vitest
1-创建vite+vue3.0+ts 项目
在敲代码之前,我们先初始化一个专门写图形组件的项目。
1.建立vue 项目。我选择vue并没有什么其它目的,你若喜欢,用react也行。
npm create vite
√ Project name: canvas-lmm
√ Select a framework: » Vue
√ Select a variant: » TypeScript
Scaffolding project in D:\work\canvas引擎\canvas-stamp...
Done. Now run:
cd canvas-lmm
npm install
npm run dev
这个项目的名称是canvas-lmm,我会用TypeScript来开发。
目前TypeScript已经是图形项目的标配了,这是我们走图形路线的同学必须要掌握的。
TypeScript很简单,所以我在后面的课程里不会对其进行系统讲解,但我会遇到什么说什么。
2.按照上面的提示进入项目,安装依赖,运行项目。
cd canvas-stamp
npm install
npm run dev
效果如下:
3.安装vitest,方便代码测试。
npm install -D vitest
tsconfig.json 的内容如下:
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"noEmit": true,
"suppressImplicitAnyIndexErrors": true,
"ignoreDeprecations": "5.0"
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
4.安装vue-router,方便创建多个测试页面。
npm install vue-router@4
2-创建绘图测试页面
这里的测试页面主要是用于测试组件的绘图功能的。
1.把src 中的components 目录改成examples,我们要在其中创建测试案例。
2.建立路由文件
- /src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
component: () => import('../examples/HelloWorld.vue'),
},
]
const router = createRouter({
history: createWebHistory(),
routes,
})
export default router
3.修改examples/HelloWorld.vue 中的代码。
- /src/examples/HelloWorld.vue
<script setup lang="ts">
import { ref, onMounted } from 'vue'
// 获取父组件属性
defineProps({
size: { type: Object, default: { width: 0, height: 0 } },
})
// 对应canvas 画布的Ref对象
const canvasRef = ref<HTMLCanvasElement>()
onMounted(() => {
const canvas = canvasRef.value
const ctx = canvas?.getContext('2d')
ctx?.fillRect(100, 100, 100, 100)
})
</script>
<template>
<canvas ref="canvasRef" :width="size.width" :height="size.height"></canvas>
</template>
<style scoped>
</style>
我在上面的vue页面中创建了一张canvas画布,并在其中绘制了一个黑色正方形。
canvas画布的尺寸是从父组件中获取的。
4.在main.ts中应用路由。
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
5.修改一下src中style.css的样式。
html {
height: 100%;
}
body {
margin: 0;
height: 100%;
overflow: hidden;
}
#app {
height: 100%;
display: flex;
}
6.在App.vue 中创建导航栏,并显示相应路由。
<script setup lang="ts">
import { onMounted, ref } from 'vue'
/* canvas 容器 */
const contRef = ref<HTMLDivElement>()
const size = ref<{
width: number | undefined
height: number | undefined
}>({
width: 0,
height: 0,
})
onMounted(() => {
// 获取canvas 容器的尺寸
const cont = contRef.value
size.value.width = cont?.clientWidth
size.value.height = cont?.clientHeight
})
</script>
<template>
<!-- 路由出口 -->
<div id="cont" ref="contRef">
<!-- 将canvas容器的尺寸传给子组件 -->
<router-view :size="size"></router-view>
</div>
<!-- 导航栏 -->
<nav>
<div class="nav-tit">测试</div>
<router-link to="/">HelloWorld</router-link>
</nav>
</template>
<style scoped>
nav {
width: 200px;
padding: 15px;
border-left: 1px solid #ddd;
}
.nav-tit {
font-weight: bold;
margin-bottom: 15px;
}
nav a {
display: block;
margin-bottom: 10px;
}
#cont {
flex: 1;
}
.router-link-active {
color: #00acec;
}
</style>
最终效果如下:
3-创建vitest测试文件
vitest 使用测试组件非可视部分的运行逻辑的。
1.在src中创建_tests_ 目录,然后在其中建立一个测试文件。
- /src/tests/EventDispatcher.spec.ts
import { describe, expect, it } from 'vitest'
describe('EventDispatcher', () => {
it('功能测试', () => {
expect(1 + 1).toBe(2)
})
})
之后这个文件会用于测试事件分发器。
2.在package.json 中添加一个测试命令
{
……
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview",
"test": "vitest --root src"
},
……
}
3.执行test 命令,可见以下内容,这说明测试文件没有问题。
✓ _tests_/EventDispatcher.spec.ts (1)
Test Files 1 passed (1)
Tests 1 passed (1)
Start at 17:28:34
Duration 358ms (transform 44ms, setup 0ms, collect 29ms, tests 3ms)
4-创建图形类
接下来我们可以根据之前的关系树,创建类对象及其继承关系写出来。
- /src/lmm/core/EventDispatcher.ts
/* 事件调度器 */
export class EventDispatcher {}
- /src/lmm/objects/Object2D.ts
import { EventDispatcher } from '../core/EventDispatcher'
class Object2D extends EventDispatcher {}
export { Object2D }
- /src/lmm/objects/Img.ts
import { Object2D } from './Object2D'
class Img extends Object2D {}
export { Img }
- /src/lmm/objects/Group.ts
import { Object2D } from './Object2D'
class Group extends Object2D {}
export { Group }
- /src/lmm/core/Scene.ts
import { Group } from '../objects/Group'
class Scene extends Group {}
export { Scene }
- /src/lmm/controler/ImgControler.ts
import { Object2D } from '../objects/Object2D'
class ImgControler extends Object2D {}
export { ImgControler }
- /src/lmm/controler/OrbitControler.ts
import { EventDispatcher } from '../core/EventDispatcher'
/* 在裁剪坐标系中做轨道控制 */
class OrbitControler extends EventDispatcher {}
export { OrbitControler }
- /src/lmm/core/Camera.ts
class Camera {}
export { Camera }
这个框架会涵盖图案编辑器的大部分
总结
当前的图形项目是与T恤编辑器的业务逻辑相分离的,这样可以让我们更专注于图形组件的开发。
转载自:https://juejin.cn/post/7244407068110602297