当前位置: 首页 > news >正文

Vue趣味【Vue3+Element Plus+Canvas实现一个简易画板;支持导出为图片】

目录

  • 🌟前言
  • 🌟粉丝先看
  • 🌟创建Vue3项目
  • 🌟引入Element Plus
  • 🌟实现代码(详细注释)
  • 🌟写在最后
  • 🌟JSON包里写函数,关注博主不迷路

🌟前言

哈喽小伙伴们,上一期给大家总结了一些常见的Vue实战中的经常用到的Vue小魔法,私下也收到了好多小伙伴的补充;小伙伴们实在是太强啦,和大家一起共同学习进步真的很开心。今天博主使用Vue3,结合ElementPlus和Canvas实现一个建议的画板,支持将绘画作品导出为图片哦;一起来看下吧。

🌟粉丝先看

博主实在没有绘画细胞大家别笑

🌟创建Vue3项目

1.使用vite构建一个vue3项目

npm create vite@latest

在这里插入图片描述

Project name:你的项目名;
Select a framework:框架选择Vue;
Select a variant:语言选择TypeSceript

cd vite-project
npm install
npm run dev

这样你的项目就创建好了

🌟引入Element Plus

Element-Plus官网国内站点

使用包管理器

我们建议您使用包管理器(如 NPM、Yarn 或 pnpm)安装 Element Plus,然后您就可以使用打包工具,例如 Vite 或 webpack。

# 选择一个你喜欢的包管理器# NPM
$ npm install element-plus --save# Yarn
$ yarn add element-plus# pnpm
$ pnpm install element-plus

如果您的网络环境不好,建议使用相关镜像服务 cnpm 或 中国 NPM 镜像

浏览器直接引入

直接通过浏览器的 HTML 标签导入 Element Plus,然后就可以使用全局变量 ElementPlus 了。 根据不同的 CDN 提供商有不同的引入方式, 我们在这里以 unpkg 和 jsDelivr 举例。 你也可以使用其它的 CDN 供应商。

unpkg

<head><!-- Import style --><link rel="stylesheet" href="//unpkg.com/element-plus/dist/index.css" /><!-- Import Vue 3 --><script src="//unpkg.com/vue@3"></script><!-- Import component library --><script src="//unpkg.com/element-plus"></script>
</head>

jsDelivr

<head><!-- Import style --><linkrel="stylesheet"href="//cdn.jsdelivr.net/npm/element-plus/dist/index.css"/><!-- Import Vue 3 --><script src="//cdn.jsdelivr.net/npm/vue@3"></script><!-- Import component library --><script src="//cdn.jsdelivr.net/npm/element-plus"></script>
</head>

完整引入

// main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'const app = createApp(App)app.use(ElementPlus)
app.mount('#app')

按需导入

首先你需要安装unplugin-vue-components 和 unplugin-auto-import这两款插件

npm install -D unplugin-vue-components unplugin-auto-import

然后把下列代码插入到你的 Vite 的配置文件中

// vite.config.ts
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'export default defineConfig({// ...plugins: [// ...AutoImport({resolvers: [ElementPlusResolver()],}),Components({resolvers: [ElementPlusResolver()],}),],
})

🌟实现代码(详细注释)

<template><div id="content"><div class="toolBar"><el-button @click="clear">清空</el-button><el-button @click="exprot">导出</el-button><el-button @click="eraser">{{ text }}</el-button><div style="margin-left: 12px"><!-- Element-Plus 颜色选择器 --><el-color-picker  v-model="color1" @change="colorChange"/></div><div style="margin-left: 12px;width: 100px"><!-- Element-Plus 滑块 --><el-slider style="margin-left: 12px;width: 100px" v-model="value1" @change="numberChange"/></div><!-- 右上方关闭按钮 --><div class="light" @click="backIndex"><div></div><div></div><div></div><div></div>X</div></div><canvas id="myCanvas"></canvas></div>
</template><script setup lang="ts">import {reactive, ref, toRefs, onBeforeMount, onMounted, nextTick} from 'vue'import {useRouter} from "vue-router";import icon from '../../assets/pen2.png'// 初始文字const text = ref('橡皮擦')// 该变量用来记录按钮文本const textFlag = ref(true)// 初始颜色const color1 = ref('#409EFF')// 初始线条粗细const value1 = ref(6)// 光标自定义const cursorIcon = ref(`url(${icon}),default`);let myCanvas: HTMLElement | nulllet ctx: { scale: (arg0: number, arg1: number) => void; moveTo: (arg0: number, arg1: number) => void; beginPath: () => void; lineWidth: any; strokeStyle: any; lineTo: (arg0: number, arg1: number) => void; stroke: () => void; }let isMouseDown: booleanlet strokeStyle: stringlet lineWidth: numberonMounted(() => {nextTick(() => {initCanvas()})})//返回首页const router = useRouter();function backIndex() {router.push('/')}// 初始化canvasfunction initCanvas() {// 线条细节处理,分辨率let dpr = window.devicePixelRatio || 1;myCanvas = document.getElementById('myCanvas')// 设置canvas实际尺寸myCanvas.width = window.innerWidth - 20myCanvas.height = window.innerHeight - 50// 让canvas坐标系统使用css像素ctx = myCanvas.getContext('2d');ctx.scale(dpr, dpr);// 监听canvas的鼠标按下时间myCanvas.addEventListener('mousedown', function (e) {// console.log(e);isMouseDown = true // 变量记录是否按下鼠标ctx.moveTo(e.pageX, e.pageY) // 将绘制起始点设置为鼠标按下的点// 设置绘制图形的样式:线条宽度和颜色;开始画线ctx.beginPath();ctx.lineWidth =  lineWidth || value1.value;ctx.strokeStyle = strokeStyle || color1.value;})// 监听鼠标松开事件myCanvas.addEventListener('mousemove', function (e) {if (isMouseDown) { // 如果鼠标按下ctx.lineTo(e.pageX, e.pageY) // 设置终点ctx.stroke() // 连接起点和终点并用设置好的样式描边}})// 监听鼠标松开事件,停止绘制myCanvas.addEventListener('mouseup', function () {// ctx.closePath();isMouseDown = false})}// 清空function clear() {// 1. 简单填充 使用一个新的背景色简单地填充整个画布,这样就可以清除当前内容// ctx.fillStyle = '#fff';// let rect = this.canvas.getBoundingClientRect();// ctx.fillRect(rect.x, rect.y, rect.width, rect.height)// 2.重置画布高度 当画布的宽或高被重置时,当前画布内容就会被移除。let rect = myCanvas.getBoundingClientRect();myCanvas.width = rect.width;myCanvas.height = rect.height;//3. 使用clearRect函数 clearRect() 函数可以指定起始点的x, y 位置以及宽度和高度来清除画布// let rect = this.canvas.getBoundingClientRect();// this.ctx.clearRect(rect.x, rect.y, rect.width, rect.height);}// 导出function exprot() {let link = document.createElement('a')link.href = myCanvas.toDataURL('image/png')link.download = 'draw.png'link.click()}// 改变颜色function colorChange(e: string | undefined) {console.log(e)strokeStyle = <string>e}// 改变线条粗细function numberChange(e: number) {lineWidth = e}// 橡皮擦,更换文本以及光标样式function eraser(e: string | undefined) {textFlag.value = !textFlag.valueconsole.log(textFlag.value)if (!textFlag.value){cursorIcon.value = "url(/src/assets/rubber.png),default"text.value = '画笔'strokeStyle = '#ffffff'}else{cursorIcon.value = 'url(/src/assets/pen2.png),default'text.value = '橡皮擦'colorChange(e)}}</script><style scoped lang="scss">html,body {width: 100%;height: 100%;margin: 0;box-sizing: border-box;overflow-y: hidden;overflow-x: hidden;}#content {width: 100%;height: 100%;position: relative;}.toolBar {width: 100vw;height: 50px;background-color: azure;box-shadow: 0 5px 2px #e8e8e8;position: absolute;top: 0;left: 0;display: flex;align-items: center;padding: 20px;box-sizing: border-box;}// 关闭按钮样式以及动画:霓虹灯效果.light {width: 40px;height: 30px;position: absolute;top: 30px;right: 30px;transform: translate(-50%, -50%);text-align: center;line-height: 30px;color: #03e9f4;font-size: 20px;text-transform: uppercase;transition: 0.5s;letter-spacing: 4px;cursor: pointer;overflow: hidden;}.light:hover {background-color: #03e9f4;color: #050801;box-shadow: 0 0 5px #03e9f4,0 0 25px #03e9f4,0 0 50px #03e9f4,0 0 200px #03e9f4;}.light div {position: absolute;}.light div:nth-child(1) {width: 100%;height: 2px;top: 0;left: -100%;background: linear-gradient(to right, transparent, #03e9f4);animation: animate1 1s linear infinite;}.light div:nth-child(2) {width: 2px;height: 100%;top: -100%;right: 0;background: linear-gradient(to bottom, transparent, #03e9f4);animation: animate2 1s linear infinite;animation-delay: 0.25s;}.light div:nth-child(3) {width: 100%;height: 2px;bottom: 0;right: -100%;background: linear-gradient(to left, transparent, #03e9f4);animation: animate3 1s linear infinite;animation-delay: 0.5s;}.light div:nth-child(4) {width: 2px;height: 100%;bottom: -100%;left: 0;background: linear-gradient(to top, transparent, #03e9f4);animation: animate4 1s linear infinite;animation-delay: 0.75s;}@keyframes animate1 {0% {left: -100%;}50%,100% {left: 100%;}}@keyframes animate2 {0% {top: -100%;}50%,100% {top: 100%;}}@keyframes animate3 {0% {right: -100%;}50%,100% {right: 100%;}}@keyframes animate4 {0% {bottom: -100%;}50%,100% {bottom: 100%;}}#myCanvas {cursor: v-bind(cursorIcon) ;overflow-y: hidden;overflow-x: hidden;}
</style>

🌟写在最后

以上就是实现简易画板的全部代码了,画出来的作品实在有点丑小伙伴们不要介意哈哈哈;大家也可以去试试,后续我会把一些图形加入进去实现拖拽等效果。喜欢的小伙伴们可以支持一下博主;你们的支持就是我创作的动力。各位小伙伴让我们 let’s be prepared at all times!

🌟JSON包里写函数,关注博主不迷路

原创不易,还希望各位大佬支持一下!
👍 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富!

相关文章:

Vue趣味【Vue3+Element Plus+Canvas实现一个简易画板;支持导出为图片】

目录&#x1f31f;前言&#x1f31f;粉丝先看&#x1f31f;创建Vue3项目&#x1f31f;引入Element Plus&#x1f31f;实现代码&#xff08;详细注释&#xff09;&#x1f31f;写在最后&#x1f31f;JSON包里写函数&#xff0c;关注博主不迷路&#x1f31f;前言 哈喽小伙伴们&a…...

【Spring Cloud Alibaba】2.服务注册与发现(Nacos安装)

文章目录环境要求简介安装Nacos源码安装Docker安装数据库配置访问服务我们要搭建一个Spring Cloud Alibaba项目就绕不开Nacos&#xff0c;阿里巴巴提供的Nacos组件&#xff0c;可以提供服务注册与发现和分布式配置服务&#xff0c;拥有着淘宝双十一十几年的流量经验&#xff0c…...

深度学习 Day28——利用Pytorch实现好莱坞明星识别

深度学习 Day28——利用Pytorch实现好莱坞明星识别 文章目录深度学习 Day28——利用Pytorch实现好莱坞明星识别一、前言二、我的环境三、前期工作1、导入依赖项设置GPU2、导入数据集3、划分数据集四、调用官方的VGG16模型五、训练模型1、编写训练函数2、编写测试函数3、设置动态…...

Android中使用FCM进行消息推送

Firebase Cloud Message 的介绍 Firebase Cloud Message(FCM)是由Google推出的一种云端消息推送服务,它是由Google推出的Google Cloud Messaging(GCM)服务的升级版。在2016年5月,Google宣布将Google Cloud Messaging重命名为Firebase Cloud Message,作为Firebase的一部…...

从 X 入门Pytorch——BN、LN、IN、GN 四种归一化层的代码使用和原理

Pytorch中四种归一化层的原理和代码使用前言1 Batch Normalization&#xff08;2015年提出&#xff09;Pytorch官网解释原理Pytorch代码示例2 Layer Normalization&#xff08;2016年提出&#xff09;Pytorch官网解释原理Pytorch代码示例3 Instance Normalization&#xff08;2…...

Windows环境下实施域名访问的一些小知识

文章目录 前言一、windows域名访问流程二、网络域名访问配置设置DNS未正确设置DNS的结果三、本地hosts设置本地hosts本地hosts的优先机制本地hosts的内部访问次序示例一示例二总结前言 作为一种常见的操作系统,windows系统具有其特殊的域名访问管理机制。了解其访问机制,将有…...

78.qt QCustomPlot介绍

参考https://www.qcustomplot.com/index.php/tutorials/settingup 下载地址: https://www.qcustomplot.com/index.php/download 1.添加帮助文档 在QtCreator ——>工具——>选项——>帮助——>文档——>添加,选择qcustomplot.qch文件,确定,以后按F1就能跳转到…...

win32api之文件系统管理(七)

什么是文件系统 文件系统是一种用于管理计算机存储设备上文件和目录的机制。文件系统为文件和目录分配磁盘空间&#xff0c;管理文件和目录的存储和检索&#xff0c;以及提供对它们的访问和共享&#xff0c;以下是常见的两种文件系统&#xff1a; NTFSFAT32磁盘分区容量2T32G…...

点云规则格网化,且保存原始的点云索引

点云规则格网化&#xff0c;且保存原始的点云索引 点云深度学习Voxelize规则&#xff0c;参考PTV2&#xff1a;https://github.com/Gofinge/PointTransformerV2 1总执行文件 import numpy as np import torch from pcr.utils.registry import Registry TRANSFORMS Registry…...

入职第一天就被迫离职,找工作多月已读不回,面试拿不到offer我该怎么办?

大多数情况下&#xff0c;测试员的个人技能成长速度&#xff0c;远远大于公司规模或业务的成长速度。所以&#xff0c;跳槽成为了这个行业里最常见的一个词汇。 前言 前几天&#xff0c;我们一个粉丝跟我说&#xff0c;正常入职一家外包&#xff0c;什么都准备好了&#xff0…...

走进Vue【三】vue-router详解

目录&#x1f31f;前言&#x1f31f;路由&#x1f31f;什么是前端路由&#xff1f;&#x1f31f;前端路由优点缺点&#x1f31f;vue-router&#x1f31f;安装&#x1f31f;路由初体验1.路由组件router-linkrouter-view2.步骤1. 定义路由组件2. 定义路由3. 创建 router 实例4. 挂…...

html+css制作

<!DOCTYPE html> <html><head><meta charset"utf-8"><title>校园官网</title><style type"text/css">*{padding: 0;margin: 0;}#logo{width:30%;float: left;}.nav{width: 100%;height: 100px;background-color…...

Python实现rar、zip和7z文件的压缩和解压

一、7z压缩文件的压缩和解压 1、安装py7zr 我们要先安装py7zr第三方库&#xff1a; pip install py7zr如果python环境有问题&#xff0c;执行上面那一条安装语句老是安装在默认的python环境的话&#xff0c;我们可以执行下面这条语句&#xff0c;将第三方库安装在项目的虚拟…...

从Hive源码解读大数据开发为什么可以脱离SQL、Java、Scala

从Hive源码解读大数据开发为什么可以脱离SQL、Java、Scala 前言 【本文适合有一定计算机基础/半年工作经验的读者食用。立个Flg&#xff0c;愿天下不再有肤浅的SQL Boy】 谈到大数据开发&#xff0c;占据绝大多数人口的就是SQL Boy&#xff0c;不接受反驳&#xff0c;毕竟大…...

RocketMQ 事务消息 原理及使用方法解析

&#x1f34a; Java学习&#xff1a;Java从入门到精通总结 &#x1f34a; 深入浅出RocketMQ设计思想&#xff1a;深入浅出RocketMQ设计思想 &#x1f34a; 绝对不一样的职场干货&#xff1a;大厂最佳实践经验指南 &#x1f4c6; 最近更新&#xff1a;2023年3月24日 &#x…...

为什么 ChatGPT 输出时经常会中断,需要输入“继续” 才可以继续输出?

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;蚂蚁集团高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《EffectiveJava》独家解析》专栏作者。 热门文章推荐…...

PyTorch 之 基于经典网络架构训练图像分类模型

文章目录一、 模块简单介绍1. 数据预处理部分2. 网络模块设置3. 网络模型保存与测试二、数据读取与预处理操作1. 制作数据源2. 读取标签对应的实际名字3. 展示数据三、模型构建与实现1. 加载 models 中提供的模型&#xff0c;并且直接用训练的好权重当做初始化参数2. 参考 pyto…...

Scrapy的callback进入不了回调方法

一、前言 有的时候&#xff0c;Scrapy的callback方法直接被略过了&#xff0c;不去执行其中的回调方法&#xff0c;可能排查好久都排查不出来&#xff0c;我来教大家集中解决方法。 yield Request(urlurl, callbackself.parse_detail, cb_kwargs{item: item})二、解决方法 1…...

第二十一天 数据库开发-MySQL

目录 数据库开发-MySQL 前言 1. MySQL概述 1.1 安装 1.2 数据模型 1.3 SQL介绍 1.4 项目开发流程 2. 数据库设计-DDL 2.1 数据库操作 2.2 图形化工具 2.3 表操作 3. 数据库操作-DML 3.1 增加(insert) 3.2 修改(update) 3.3 删除(delete) 数据库开发-MySQL 前言 …...

蓝桥杯每日一真题—— [蓝桥杯 2021 省 AB2] 完全平方数(数论,质因数分解)

文章目录[蓝桥杯 2021 省 AB2] 完全平方数题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1样例 #2样例输入 #2样例输出 #2提示思路&#xff1a;理论补充&#xff1a;完全平方数的一个性质&#xff1a;完全平方数的质因子的指数一定为偶数最终思路&#xff1a;小插曲&am…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

安卓基础(Java 和 Gradle 版本)

1. 设置项目的 JDK 版本 方法1&#xff1a;通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分&#xff0c;设置 Gradle JDK 方法2&#xff1a;通过 Settings File → Settings... (或 CtrlAltS)…...

算法打卡第18天

从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…...