vue 版本 canvas 绘图工具来啦!像写 React Native(RN)一样实现canvas 绘图任务

跟大家分享一下我实现的一个小工具:@sketchjs

小程序使用的话占用包体积比较大,taro主包体积优化插件已经在路上了哈可以等一等

给大家介绍一个我实现的一个小工具 ------@sketchjs。它能实现像写 React Native(RN)一样,相对轻松地完成绘图任务。接下来,就详细跟大家唠唠它。

一、安装轻松上手

  • 要是你习惯 npm,在命令行输入下面这行就行:
shell 复制代码
npm install @sketchjs/vue
  • 喜欢 yarn 的话,就执行:
shell 复制代码
yarn add @sketchjs/vue
  • pnpm 的朋友,输入:
shell 复制代码
pnpm add @sketchjs/vue

二、多平台支持

不管是 H5 页面,还是 Taro 小程序,都能稳稳地发挥作用。

(一)H5环境中

codesandbox 中打开

  • 首先,得在vue项目 vite.config.ts 中配置以下内容:
javascript 复制代码
import { defineConfig } from 'vite'
// https://vite.dev/config/
export default defineConfig({
  define:{
    'process.env.SKETCH_PLATFORM': '"WEB"', // 使用小程序端 sketch 实现
    'process.env.YOGA_USE_WASM': 'false' // 不使用 WASM 实现
  },
  optimizeDeps: {
    include: ['@sketchjs/vue'],
  },
})

在 H5 环境里,可以通过以下代码进行简单的Canvas绘制:

js 复制代码
<template>
  <div class="App" @click="handleToDataURL">
    <canvas class="sketch-canvas" ref="canvasRef"/>
    <Sketch.Root :style="style.root" :sketch="sketch" @ready="handleSketchInitialized" @update="handleSketchUpdate">
      <Sketch.View :style="style.view">
        <Sketch.Image :src="logo" :style="style.logo"/>
        <Sketch.Text text="Hello  World!" :style="style.text"/>
      </Sketch.View>
    </Sketch.Root>
  </div>
</template>

<script setup lang="ts">
import logo from '@/assets/logo.svg'
import { onMounted, ref } from 'vue'
import { StyleSheet, Sketch } from '@sketchjs/vue'

Sketch.debug = true

const style = StyleSheet.create({
  root: {
    width: 500,
    height: 500,
    backgroundColor: '#ffffff'
  },
  view: {
    width: 500,
    height: 500,
    justifyContent: 'center',
    alignItems: 'center'
  },
  logo: {
    width: 262,
    height: 227
  },
  text: {
    width: 500,
    marginTop: 20,
    color: '#282c34',
    fontSize: 50,
    fontWeight: 400,
    lineHeight: 50,
    textAlign: 'center'
  }
})

const sketch = Sketch.useSketch()

const canvasRef = ref<HTMLCanvasElement | null>(null)

const initCanvas = () => {
  const canvas = canvasRef.value
  const ctx = canvas?.getContext('2d')
  if (!canvas || !ctx) return
  return sketch.value.init({ canvas, ctx })
}

onMounted(() => initCanvas())

const handleToDataURL = () => {
  const dataUrl = sketch.value.toDataURL('image/png', 1)
  console.log({ dataUrl })
}

const handleSketchUpdate = () => {
  console.log('sketch update')
}

const handleSketchInitialized = () => {
  console.log('sketch initialized')
}
</script>

<style scoped>
.App {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;

  .sketch-canvas{
    width: 500px;
    height: 500px;
  }
}
</style>

(二)Taro 小程序中

在 Taro 小程序这边,@sketchjs 同样没让人失望。

  • 首先,得在taro项目 config/index.ts 中配置下环境变量:
ts 复制代码
import { defineConfig } from '@tarojs/cli';

export default defineConfig({
    defineConstants: {
        'process.env.SKETCH_PLATFORM': '"APPLET"',  // 使用小程序端 sketch 实现
        'process.env.YOGA_USE_WASM': 'false',  // 不使用 WASM 实现
    },
});
  • 接着就是具体的示例代码,和 H5 那边有些类似:
js 复制代码
<template>
  <View @tap="handleToDataURL" class='index-view'>
    <Canvas id='sketch-canvas' type='2d' class='sketch-canvas' />
    <Sketch.Root :style="style.root" :sketch="sketch" @ready="handleSketchInitialized" @update="handleSketchUpdate">
      <Sketch.View :style="style.view">
        <Sketch.Image :src="require('@/assets/logo.svg')" :style="style.logo"/>
        <Sketch.Text text="Hello  World!" :style="style.text"/>
      </Sketch.View>
    </Sketch.Root>
  </View>
</template>

<script setup lang="ts">
import { defineComponent, onMounted } from 'vue'
import { View, Canvas } from '@tarojs/components'
import { StyleSheet, Sketch } from '@sketchjs/vue'
import Taro from '@tarojs/taro'
import './index.less'

defineComponent({ name: 'IndexPage' })

Sketch.debug = true

const style = StyleSheet.create({
  root: {
    width: 500,
    height: 500,
    backgroundColor: '#fff'
  },
  view: {
    width: 500,
    height: 500,
    justifyContent: 'center',
    alignItems: 'center'
  },
  logo: {
    width: 262,
    height: 227
  },
  text: {
    width: 500,
    marginTop: 20,
    color: '#282c34',
    fontSize: 50,
    fontWeight: 400,
    lineHeight: 50,
    textAlign: 'center'
  }
})

const sketch = Sketch.useSketch()

const initCanvas = async () => {
  const canvasNode: HTMLCanvasElement = await new Promise((resolve) => {
    const selectorQuery = Taro.createSelectorQuery()
    const callback = (res:any) => resolve(res?.node)
    selectorQuery.select('#sketch-canvas').fields({ node: true }, callback).exec()
  })
  const canvasCtx = canvasNode.getContext('2d')
  if (!canvasNode || !canvasCtx) return
  return sketch.value.init({ canvas: canvasNode, ctx: canvasCtx }).then(() => sketch.value.render())
}

onMounted(() => initCanvas())

const handleToDataURL = () => {
  const dataUrl = sketch.value.toDataURL('image/png', 1)
  console.log({ dataUrl })
}

const handleSketchUpdate = () => {
  console.log('sketch update')
}

const handleSketchInitialized = () => {
  console.log('sketch initialized')
}

</script>

三、关键绘图组件

@sketchjs/react 和 RN 开发模式相似,用起来比较容易上手。

(一)<Sketch.Root> 组件

在代码里,咱们用 StyleSheet.create 来定义样式赋予它宽高。比如说:

js 复制代码
<template>
  <Sketch.Root :style="style.root" />
</template>
<script setup lang="ts">
import { StyleSheet, Sketch } from '@sketchjs/vue'

const style = StyleSheet.create({
    root: {
        width: 500,
        height: 500
    }
});
</script>

(二)<Sketch.View> 组件

<Sketch.View> 在绘图区域内划分出一个个子区域,用于对绘图元素进行分组管理。通过 style 属性,我们能运用熟悉的 CSS 布局技巧对其进行调控。以常见的居中布局为例,在代码中:

js 复制代码
<template>
    <Sketch.Root>
        <Sketch.View :style="style.rootView" >
        {/* 这里面放图片、文本等绘图子组件,它们就能按设定布局展示 */}
        </Sketch.View>
    </Sketch.Root>
</template>
<script setup lang="ts">
import { StyleSheet, Sketch } from '@sketchjs/vue'

const style = StyleSheet.create({
    rootView: {
        width: 500,
        height: 500
    }
});
</script>
  • style.rootView 样式对象定义了子区域的宽度与高度均为 500justifyContent: 'center' 使得子组件在水平方向上居中对齐,alignItems: 'center' 让子组件在垂直方向上也居中对齐。
  • 这样一来,不管是 <Sketch.Image> 展示的图片,还是 <Sketch.Text> 呈现的文本,都能在这个子区域内找到合适的展示位置,布局整整齐齐的。

(三)<Sketch.Image> 组件

<Sketch.Image> 功能很明确,就是把图片展示在 Canvas 绘图区域里。咱们只要给 src 属性指定图片的路径就行,超级简单。

结合 StyleSheet.create 定义样式来看个例子:

js 复制代码
<template>
    <Sketch.Root>
        <Sketch.View :style="style.rootView" >
            <Sketch.Image src={myImage} style={style.imageStyle} />
        </Sketch.View>
    </Sketch.Root>
</template>

<script setup lang="ts">
import { StyleSheet, Sketch } from '@sketchjs/vue'
import myImage from './myImage.png'; // 这里引入实际的图片资源

const style = StyleSheet.create({
    imageStyle: {
        width: 200,
        height: 200,
        marginLeft: 50, // 还可以设置图片的边距等样式,按需调整
    },
});
</script>
  • 通过 src 属性把 myImage(指向实际图片文件的路径)传给 <Sketch.Image> 组件,
  • 然后用 StyleSheet.create 生成的 style.imageStyle 来设置图片尺寸,像这里设置宽度 200 像素,高度 200 像素,
  • 还可以通过其他属性调整图片位置,这样图片就能以咱们想要的样子出现在绘图区域,给画面添彩。

(四)<Sketch.Text> 组件

<Sketch.Text> 组件负责在绘图区域里显示文字内容。咱们用 text 属性写上要显示的文字,再用 style 属性设置字体、大小、颜色、对齐方式这些,文字就能自然融入绘图。

比如这个例子:

js 复制代码
<template>
    <Sketch.Root>
        <Sketch.View :style="style.rootView" >
           <Sketch.Text text="Hello  World!" style={style.textStyle} />
        </Sketch.View>
    </Sketch.Root>
</template>

<script setup lang="ts">
import { StyleSheet, Sketch } from '@sketchjs/vue'
import myImage from './myImage.png'; // 这里引入实际的图片资源

const style = StyleSheet.create({
    textStyle: {
        width: 500,
        marginTop: 20,
        color: '#ffffff',
        fontSize: 50,
        fontWeight: 400,
        lineHeight: 50,
        textAlign: 'center'
    },
});
</script>
  • 在这个例子里,text 属性写上 "Hello World!"
  • style.textStyle 样式对象里设置了文字颜色为白色、字体大小 50 像素、居中对齐等
  • 这样文字就能在绘图区域里以合适的样子出现,和图片等其他元素搭配起来,共同完成绘图效果。

四、总结

总的来说,@sketchjs/vue 开发体验还不错,能让咱们像写 RN 代码一样相对轻松地搞定 Canvas 2D 绘图。要是你在绘图开发上也遇到难题,不妨试试它,说不定能帮你省不少事儿,让你的项目绘图功能实现得更顺利。希望对大家的Canvas绘图开发有点帮助。

目前@sketchjs/vue还是alpha版本。要是在使用的过程中有什么问题,欢迎提issues随时交流。

如果这个库在canvas开发中帮到了你,请给个赞或者githubstar

本文由豆包AI生成如有错漏,辛苦指正。

链接地址

npm 地址

github 仓库地址

相关推荐
weifexie23 分钟前
ruby可变参数
开发语言·前端·ruby
千野竹之卫25 分钟前
3D珠宝渲染用什么软件比较好?渲染100邀请码1a12
开发语言·前端·javascript·3d·3dsmax
sunbyte25 分钟前
初识 Three.js:开启你的 Web 3D 世界 ✨
前端·javascript·3d
半兽先生1 小时前
WebRtc 视频流卡顿黑屏解决方案
java·前端·webrtc
南星沐2 小时前
Spring Boot 常用依赖介绍
java·前端·spring boot
孙_华鹏2 小时前
手撸一个可以语音操作高德地图的AI智能体
前端·javascript·coze
zhangxingchao2 小时前
Jetpack Compose 动画
前端
@PHARAOH3 小时前
HOW - 缓存 React 自定义 hook 的所有返回值(包括函数)
前端·react.js·缓存
拉不动的猪3 小时前
设计模式之--------工厂模式
前端·javascript·架构
前端开发张小七3 小时前
16.Python递归详解:从原理到实战的完整指南
前端·python