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实现一个简易画板;支持导出为图片】
目录🌟前言🌟粉丝先看🌟创建Vue3项目🌟引入Element Plus🌟实现代码(详细注释)🌟写在最后🌟JSON包里写函数,关注博主不迷路🌟前言 哈喽小伙伴们&a…...

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

深度学习 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(2015年提出)Pytorch官网解释原理Pytorch代码示例2 Layer Normalization(2016年提出)Pytorch官网解释原理Pytorch代码示例3 Instance Normalization(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之文件系统管理(七)
什么是文件系统 文件系统是一种用于管理计算机存储设备上文件和目录的机制。文件系统为文件和目录分配磁盘空间,管理文件和目录的存储和检索,以及提供对它们的访问和共享,以下是常见的两种文件系统: NTFSFAT32磁盘分区容量2T32G…...
点云规则格网化,且保存原始的点云索引
点云规则格网化,且保存原始的点云索引 点云深度学习Voxelize规则,参考PTV2:https://github.com/Gofinge/PointTransformerV2 1总执行文件 import numpy as np import torch from pcr.utils.registry import Registry TRANSFORMS Registry…...

入职第一天就被迫离职,找工作多月已读不回,面试拿不到offer我该怎么办?
大多数情况下,测试员的个人技能成长速度,远远大于公司规模或业务的成长速度。所以,跳槽成为了这个行业里最常见的一个词汇。 前言 前几天,我们一个粉丝跟我说,正常入职一家外包,什么都准备好了࿰…...

走进Vue【三】vue-router详解
目录🌟前言🌟路由🌟什么是前端路由?🌟前端路由优点缺点🌟vue-router🌟安装🌟路由初体验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第三方库: pip install py7zr如果python环境有问题,执行上面那一条安装语句老是安装在默认的python环境的话,我们可以执行下面这条语句,将第三方库安装在项目的虚拟…...

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

RocketMQ 事务消息 原理及使用方法解析
🍊 Java学习:Java从入门到精通总结 🍊 深入浅出RocketMQ设计思想:深入浅出RocketMQ设计思想 🍊 绝对不一样的职场干货:大厂最佳实践经验指南 📆 最近更新:2023年3月24日 &#x…...

为什么 ChatGPT 输出时经常会中断,需要输入“继续” 才可以继续输出?
作者:明明如月学长, CSDN 博客专家,蚂蚁集团高级 Java 工程师,《性能优化方法论》作者、《解锁大厂思维:剖析《阿里巴巴Java开发手册》》、《再学经典:《EffectiveJava》独家解析》专栏作者。 热门文章推荐…...

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

Scrapy的callback进入不了回调方法
一、前言 有的时候,Scrapy的callback方法直接被略过了,不去执行其中的回调方法,可能排查好久都排查不出来,我来教大家集中解决方法。 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提示思路:理论补充:完全平方数的一个性质:完全平方数的质因子的指数一定为偶数最终思路:小插曲&am…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...

恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...