当前位置: 首页 > 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…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...

前端中slice和splic的区别

1. slice slice 用于从数组中提取一部分元素&#xff0c;返回一个新的数组。 特点&#xff1a; 不修改原数组&#xff1a;slice 不会改变原数组&#xff0c;而是返回一个新的数组。提取数组的部分&#xff1a;slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...

恶补电源:1.电桥

一、元器件的选择 搜索并选择电桥&#xff0c;再multisim中选择FWB&#xff0c;就有各种型号的电桥: 电桥是用来干嘛的呢&#xff1f; 它是一个由四个二极管搭成的“桥梁”形状的电路&#xff0c;用来把交流电&#xff08;AC&#xff09;变成直流电&#xff08;DC&#xff09;。…...

写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里

写一个shell脚本&#xff0c;把局域网内&#xff0c;把能ping通的IP和不能ping通的IP分类&#xff0c;并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...