uni-app canvas 签名

在这里插入图片描述
调用方法

import Signature from "@/components/signature.vue"
const base64Img = ref()
//监听getSignImg
uni.$on('getSignImg', ({ base64, path }) => {
		base64Img.value = base64
	    //console.log('签名base64, path ====>', base64, path) //拿到的图片数据
	    // 之后取消监听,防止重复监听
	    uni.$off('getSignImg')
	})
<Signature :showMark="false"  @cancle="cancle"></Signature>

signature.vue

<template>
	<view class="sign-page" v-cloak>
		<view class="dis-flex justify-end">
			<uv-icon name="close" color="#333" size="48rpx" @click="cancle"></uv-icon>
		</view>
		<view class="sign-body">
			<canvas id="signCanvas" canvas-id="signCanvas" class="sign-canvas" disable-scroll
				@touchstart.stop="signCanvasStart" @touchmove.stop="signCanvasMove"
				@touchend.stop="signCanvasEnd"></canvas>
			<!-- #ifndef APP -->
			<!--用于临时储存横屏图片的canvas容器,H5和小程序需要-->
			<canvas v-if="horizontal" id="hsignCanvas" canvas-id="hsignCanvas"
				style="position: absolute; top: -1000px; z-index: -1"
				:style="{ width: canvasHeight + 'px', height: canvasWidth + 'px' }"></canvas>
			<!-- #endif -->
		</view>
		<view class="sign-footer" :class="[horizontal ? 'horizontal-btns' : 'vertical-btns']">
			<uv-button
				customStyle="margin-top: 20rpx;width:300rpx;height:100rpx;border-radius:20rpx;border:1px solid #3894FF"
				@click="reset">
				<uv-icon name="shuaxin" color="#3894FF" size="48rpx" custom-prefix="custom-icon"></uv-icon>
				<text class="txt">重新签字</text>
			</uv-button>

			<uv-button type="primary" text="确定提交" customTextStyle="font-size:36rpx"
				customStyle="margin-top: 20rpx;width:300rpx;height:100rpx;border-radius:20rpx"
				@click="confirm"></uv-button>
		</view>
	</view>
</template>

<script>
	import {
		pathToBase64,
		base64ToPath
	} from '@/utils/signature.js'
	export default {
		name: 'sign',
		props: {
			// 背景水印图,优先级大于 bgColor
			bgImg: {
				type: String,
				default: ''
			},
			// 背景纯色底色,为空则透明
			bgColor: {
				type: String,
				default: ''
			},
			// 是否显示水印
			showMark: {
				type: Boolean,
				default: true
			},
			// 水印内容,可多行
			markText: {
				type: Array,
				default: () => {
					return [] // ['水印1', '水印2']
				}
			},
			// 水印样式
			markStyle: {
				type: Object,
				default: () => {
					return {
						fontSize: 12, // 水印字体大小
						fontFamily: 'microsoft yahei', // 水印字体
						color: '#cccccc', // 水印字体颜色
						rotate: 60, // 水印旋转角度
						step: 2.2 // 步长,部分场景下可通过调节该参数来调整水印间距,建议为1.4-2.6左右
					}
				}
			},
			// 是否横屏
			horizontal: {
				type: Boolean,
				default: false
			},
			// 画笔样式
			penStyle: {
				type: Object,
				default: () => {
					return {
						lineWidth: 3, // 画笔线宽 建议1~5
						color: '#000000' // 画笔颜色
					}
				}
			},
			// 导出图片配置
			expFile: {
				type: Object,
				default: () => {
					return {
						fileType: 'png', // png/jpg (png不可压缩质量,支持透明;jpg可压缩质量,不支持透明)
						quality: 1 // 范围 0 - 1 (仅jpg支持)
					}
				}
			}
		},
		data() {
			return {
				canvasCtx: null, // canvascanvasWidth: 0, // canvas宽度
				canvasWidth: 0, // canvas宽度
				canvasHeight: 0, // canvas高度
				x0: 0, // 初始横坐标或上一段touchmove事件中触摸点的横坐标
				y0: 0, // 初始纵坐标或上一段touchmove事件中触摸点的纵坐标
				signFlag: false // 签名旗帜
			}
		},
		mounted() {
			this.$nextTick(() => {
				this.createCanvas()
			})
		},
		methods: {
			// 创建canvas实例
			createCanvas() {
				this.canvasCtx = uni.createCanvasContext('signCanvas', this)
				this.canvasCtx.setLineCap('round') // 向线条的每个末端添加圆形线帽

				// 获取canvas宽高
				const query = uni.createSelectorQuery().in(this)
				query
					.select('.sign-body')
					.boundingClientRect((data) => {
						this.canvasWidth = data.width
						this.canvasHeight = data.height
					})
					.exec(async () => {
						await this.drawBg()
						this.drawMark(this.markText)
					})
			},
			async drawBg() {
				if (this.bgImg) {
					const img = await uni.getImageInfo({
						src: this.bgImg
					})
					this.canvasCtx.drawImage(img.path, 0, 0, this.canvasWidth, this.canvasHeight)
				} else if (this.bgColor) {
					// 绘制底色填充,否则为透明
					this.canvasCtx.setFillStyle(this.bgColor)
					this.canvasCtx.fillRect(0, 0, this.canvasWidth, this.canvasHeight)
				}
			},
			// 绘制动态水印
			drawMark(textArray) {
				if (!this.showMark) {
					this.canvasCtx.draw()
					return
				}
				// 绘制背景
				this.drawBg()

				// 水印参数
				const markStyle = Object.assign({
						fontSize: 12, // 水印字体大小
						fontFamily: 'microsoft yahei', // 水印字体
						color: '#cccccc', // 水印字体颜色
						rotate: 60, // 水印旋转角度
						step: 2 // 步长,部分场景下可通过调节该参数来调整水印间距,建议为1.4-2.6左右
					},
					this.markStyle
				)
				this.canvasCtx.font = `${markStyle.fontSize}px ${markStyle.fontFamily}`
				this.canvasCtx.fillStyle = markStyle.color
				// 文字坐标
				const maxPx = Math.max(this.canvasWidth / 2, this.canvasHeight / 2)
				const stepPx = Math.floor(maxPx / markStyle.step)
				let arrayX = [0] // 初始水印位置 canvas坐标 0 0 点
				while (arrayX[arrayX.length - 1] < maxPx / 2) {
					arrayX.push(arrayX[arrayX.length - 1] + stepPx)
				}
				arrayX.push(
					...arrayX.slice(1, arrayX.length).map((item) => {
						return -item
					})
				)

				for (let i = 0; i < arrayX.length; i++) {
					for (let j = 0; j < arrayX.length; j++) {
						this.canvasCtx.save()
						this.canvasCtx.translate(this.canvasWidth / 2, this.canvasHeight / 2) // 画布旋转原点 移到 图片中心
						this.canvasCtx.rotate(Math.PI * (markStyle.rotate / 180))
						textArray.forEach((item, index) => {
							let offsetY = markStyle.fontSize * index
							this.canvasCtx.fillText(item, arrayX[i], arrayX[j] + offsetY)
						})
						this.canvasCtx.restore()
					}
				}

				this.canvasCtx.draw()
			},
			cancle() {
				//取消按钮事件
				this.$emit('cancle')
				this.reset()
				//uni.navigateBack()
			},
			async reset() {
				this.$emit('reset')
				this.signFlag = false
				this.canvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
				await this.drawBg()
				this.drawMark(this.markText)
			},
			async confirm() {
				this.$emit('confirm')
				// 确认按钮事件
				if (!this.signFlag) {
					uni.showToast({
						title: '请签名后再点击确定',
						icon: 'none',
						duration: 2000
					})
					return
				}

				uni.showModal({
					title: '确认',
					content: '确认签名无误吗',
					showCancel: true,
					success: async ({
						confirm
					}) => {
						if (confirm) {
							let tempFile
							if (this.horizontal) {
								tempFile = await this.saveHorizontalCanvas()
							} else {
								tempFile = await this.saveCanvas()
							}
							const base64 = await pathToBase64(tempFile)
							const path = await base64ToPath(base64)
							uni.$emit('getSignImg', {
								base64,
								path
							})
							//uni.navigateBack()
						}
					}
				})
			},
			signCanvasEnd(e) {
				// 签名抬起事件
				// console.log(e, 'signCanvasEnd')
				this.x0 = 0
				this.y0 = 0
			},
			signCanvasMove(e) {
				// 签名滑动事件
				// console.log(e, 'signCanvasMove')
				// #ifdef MP-WEIXIN
				let dx = e.touches[0].clientX - this.x0
				let dy = e.touches[0].clientY - this.y0
				// #endif
				// #ifndef MP-WEIXIN
				let dx = e.touches[0].x - this.x0
				let dy = e.touches[0].y - this.y0
				// #endif
				this.canvasCtx.moveTo(this.x0, this.y0)
				this.canvasCtx.lineTo(this.x0 + dx, this.y0 + dy)
				this.canvasCtx.setLineWidth(this.penStyle?.lineWidth || 4)
				this.canvasCtx.strokeStyle = this.penStyle?.color || '#000000'
				this.canvasCtx.stroke()
				this.canvasCtx.draw(true)
				// #ifdef MP-WEIXIN
				this.x0 = e.touches[0].clientX
				this.y0 = e.touches[0].clientY
				// #endif
				// #ifndef MP-WEIXIN
				this.x0 = e.touches[0].x
				this.y0 = e.touches[0].y
				// #endif
			},
			signCanvasStart(e) {
				// 签名按下事件 app获取的e不一样区分小程序app
				// console.log('signCanvasStart', e)
				if (!this.signFlag) {
					// 导出第一次开始触碰事件
					this.$emit('firstTouchStart')
				}
				this.signFlag = true
				// #ifdef MP-WEIXIN
				this.x0 = e.touches[0].clientX
				this.y0 = e.touches[0].clientY
				// #endif
				// #ifndef MP-WEIXIN
				this.x0 = e.touches[0].x
				this.y0 = e.touches[0].y
				// #endif
			},
			// 保存竖屏图片
			async saveCanvas() {
				return await new Promise((resolve, reject) => {
					uni.canvasToTempFilePath({
							canvasId: 'signCanvas',
							fileType: this.expFile.fileType, // 只支持png和jpg
							quality: this.expFile.quality, // 范围 0 - 1
							success: (res) => {
								if (!res.tempFilePath) {
									uni.showModal({
										title: '提示',
										content: '保存签名失败',
										showCancel: false
									})
									return
								}
								resolve(res.tempFilePath)
							},
							fail: (r) => {
								console.log('图片生成失败:' + r)
								resolve(false)
							}
						},
						this
					)
				})
			},
			// 保存横屏图片
			async saveHorizontalCanvas() {
				return await new Promise((resolve, reject) => {
					uni.canvasToTempFilePath({
							canvasId: 'signCanvas',
							fileType: this.expFile.fileType, // 只支持png和jpg
							success: (res) => {
								if (!res.tempFilePath) {
									uni.showModal({
										title: '提示',
										content: '保存签名失败',
										showCancel: false
									})
									return
								}

								// #ifdef APP
								uni.compressImage({
									src: res.tempFilePath,
									quality: this.expFile.quality * 100, // 范围 0 - 100
									rotate: 270,
									success: (r) => {
										console.log('==== compressImage :', r)
										resolve(r.tempFilePath)
									}
								})
								// #endif

								// #ifndef APP
								uni.getImageInfo({
									src: res.tempFilePath,
									success: (r) => {
										// console.log('==== getImageInfo :', r)
										// 将signCanvas的内容复制到hsignCanvas中
										const hcanvasCtx = uni.createCanvasContext(
											'hsignCanvas', this)
										// 横屏宽高互换
										hcanvasCtx.translate(this.canvasHeight / 2, this
											.canvasWidth / 2)
										hcanvasCtx.rotate(Math.PI * (-90 / 180))
										hcanvasCtx.drawImage(
											r.path,
											-this.canvasWidth / 2,
											-this.canvasHeight / 2,
											this.canvasWidth,
											this.canvasHeight
										)
										hcanvasCtx.draw(false, async () => {
											const hpathRes = await uni
												.canvasToTempFilePath({
														canvasId: 'hsignCanvas',
														fileType: this.expFile
															.fileType, // 只支持png和jpg
														quality: this.expFile
															.quality // 范围 0 - 1
													},
													this
												)
											let tempFile = ''
											if (Array.isArray(hpathRes)) {
												hpathRes.some((item) => {
													if (item) {
														tempFile = item
															.tempFilePath
														return
													}
												})
											} else {
												tempFile = hpathRes
													.tempFilePath
											}
											resolve(tempFile)
										})
									}
								})
								// #endif
							},
							fail: (err) => {
								console.log('图片生成失败:' + err)
								resolve(false)
							}
						},
						this
					)
				})
			}
		}
	}
</script>

<style scoped lang="scss">
	[v-cloak] {
		display: none !important;
	}

	.sign-page {
		height: 600rpx;
		width: 710rpx;
		padding: 20rpx;
		display: flex;
		flex-direction: column;

		.sign-body {
			margin-top: 50rpx;
			width: 100%;
			flex-grow: 1;
			background: #E5E5E5;

			.sign-canvas {
				width: 100%;
				height: 100%;
			}
		}

		.sign-footer {
			width: 100%;
			height: 80rpx;
			margin: 15rpx 0;
			display: flex;
			justify-content: space-evenly;
			align-items: center;

			.txt{
				color:#3894FF;
				padding-left:10rpx;
				font-size: 36rpx;
			}
		}

		.vertical-btns {
			.btn {
				width: 120rpx;
				height: 66rpx;
			}
		}

		.horizontal-btns {
			.btn {
				width: 66rpx;
				height: 120rpx;
				writing-mode: vertical-lr;
				transform: rotate(90deg);
			}
		}
	}

	:deep(.uvicon-close) {
		font-size: 48rpx
	}
</style>

signature.js

function getLocalFilePath(path) {
    if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) {
        return path
    }
    if (path.indexOf('file://') === 0) {
        return path
    }
    if (path.indexOf('/storage/emulated/0/') === 0) {
        return path
    }
    if (path.indexOf('/') === 0) {
        var localFilePath = plus.io.convertAbsoluteFileSystem(path)
        if (localFilePath !== path) {
            return localFilePath
        } else {
            path = path.substr(1)
        }
    }
    return '_www/' + path
}

function dataUrlToBase64(str) {
    var array = str.split(',')
    return array[array.length - 1]
}

var index = 0
function getNewFileId() {
    return Date.now() + String(index++)
}

function biggerThan(v1, v2) {
    var v1Array = v1.split('.')
    var v2Array = v2.split('.')
    var update = false
    for (var index = 0; index < v2Array.length; index++) {
        var diff = v1Array[index] - v2Array[index]
        if (diff !== 0) {
            update = diff > 0
            break
        }
    }
    return update
}

export function pathToBase64(path) {
    return new Promise(function(resolve, reject) {
        if (typeof window === 'object' && 'document' in window) {
            if (typeof FileReader === 'function') {
                var xhr = new XMLHttpRequest()
                xhr.open('GET', path, true)
                xhr.responseType = 'blob'
                xhr.onload = function() {
                    if (this.status === 200) {
                        let fileReader = new FileReader()
                        fileReader.onload = function(e) {
                            resolve(e.target.result)
                        }
                        fileReader.onerror = reject
                        fileReader.readAsDataURL(this.response)
                    }
                }
                xhr.onerror = reject
                xhr.send()
                return
            }
            var canvas = document.createElement('canvas')
            var c2x = canvas.getContext('2d')
            var img = new Image
            img.onload = function() {
                canvas.width = img.width
                canvas.height = img.height
                c2x.drawImage(img, 0, 0)
                resolve(canvas.toDataURL())
                canvas.height = canvas.width = 0
            }
            img.onerror = reject
            img.src = path
            return
        }
        if (typeof plus === 'object') {
            plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), function(entry) {
                entry.file(function(file) {
                    var fileReader = new plus.io.FileReader()
                    fileReader.onload = function(data) {
                        resolve(data.target.result)
                    }
                    fileReader.onerror = function(error) {
                        reject(error)
                    }
                    fileReader.readAsDataURL(file)
                }, function(error) {
                    reject(error)
                })
            }, function(error) {
                reject(error)
            })
            return
        }
        if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
            wx.getFileSystemManager().readFile({
                filePath: path,
                encoding: 'base64',
                success: function(res) {
                    resolve('data:image/png;base64,' + res.data)
                },
                fail: function(error) {
                    reject(error)
                }
            })
            return
        }
        reject(new Error('not support'))
    })
}

export function base64ToPath(base64) {
    return new Promise(function(resolve, reject) {
        if (typeof window === 'object' && 'document' in window) {
            base64 = base64.split(',')
            var type = base64[0].match(/:(.*?);/)[1]
            var str = atob(base64[1])
            var n = str.length
            var array = new Uint8Array(n)
            while (n--) {
                array[n] = str.charCodeAt(n)
            }
            return resolve((window.URL || window.webkitURL).createObjectURL(new Blob([array], { type: type })))
        }
        var extName = base64.split(',')[0].match(/data\:\S+\/(\S+);/)
        if (extName) {
            extName = extName[1]
        } else {
            reject(new Error('base64 error'))
        }
        var fileName = getNewFileId() + '.' + extName
        if (typeof plus === 'object') {
            var basePath = '_doc'
            var dirPath = 'uniapp_temp'
            var filePath = basePath + '/' + dirPath + '/' + fileName
            if (!biggerThan(plus.os.name === 'Android' ? '1.9.9.80627' : '1.9.9.80472', plus.runtime.innerVersion)) {
                plus.io.resolveLocalFileSystemURL(basePath, function(entry) {
                    entry.getDirectory(dirPath, {
                        create: true,
                        exclusive: false,
                    }, function(entry) {
                        entry.getFile(fileName, {
                            create: true,
                            exclusive: false,
                        }, function(entry) {
                            entry.createWriter(function(writer) {
                                writer.onwrite = function() {
                                    resolve(filePath)
                                }
                                writer.onerror = reject
                                writer.seek(0)
                                writer.writeAsBinary(dataUrlToBase64(base64))
                            }, reject)
                        }, reject)
                    }, reject)
                }, reject)
                return
            }
            var bitmap = new plus.nativeObj.Bitmap(fileName)
            bitmap.loadBase64Data(base64, function() {
                bitmap.save(filePath, {}, function() {
                    bitmap.clear()
                    resolve(filePath)
                }, function(error) {
                    bitmap.clear()
                    reject(error)
                })
            }, function(error) {
                bitmap.clear()
                reject(error)
            })
            return
        }
        if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
            var filePath = wx.env.USER_DATA_PATH + '/' + fileName
            wx.getFileSystemManager().writeFile({
                filePath: filePath,
                data: dataUrlToBase64(base64),
                encoding: 'base64',
                success: function() {
                    resolve(filePath)
                },
                fail: function(error) {
                    reject(error)
                }
            })
            return
        }
        reject(new Error('not support'))
    })
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/572364.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于51单片机的矩阵按键扫描的proteus仿真

文章目录 一、按键按键按键消抖 二、独立按键仿真图仿真程序 三、矩阵按键仿真图仿真程序 四、总结 一、按键 按键 按键通常指的是电子设备上的一种输入装置&#xff0c;用于在按下时发送信号&#xff0c;以便设备执行相应的操作。按键可以分为独立按键和矩阵按键两种类型。 …

无人机GB42590接收端 +接收端模组,同时支持2.4G与5.8G双频

严格按照GB42590的协议开发的发射端&#xff0c;通过串口和模块通讯&#xff0c;默认波特率 921600。 http://www.doit.am/深圳四博智联科技有限公司https://shenzhendoit.taobao.com/category-1734422372.htm?spma1z10.1-c-s.0.0.560c74d77eT01G&searchy&catNameGB4…

Qt开发(二)打包发布

注意qt6生成的exe不能再win7&#xff08;包含win7&#xff09;以下运行 1、编译程序 编译程序不演示 2、找到exe文件 在这个路径下找到该exe文件 3、打包 新建一个文件夹 将exe放在该文件夹下除了exe开始这里面没有其他文件 找到安装目录下 在cmd中运行 把这个文件和编…

【Java】文件大小转换工具类(B,KB,MB,G,TB,PB)

说明 使用方法&#xff1a;FileMemoryUtil.prettyByteSize(35871)&#xff0c;参数为字节个数 返回结果&#xff1a;保留一位小数的自适应结果&#xff08;例如&#xff1a;4.1KB&#xff09;。可以留意在浏览器上下载的文件&#xff0c;会根据文件大小展示不同的单位&#xff…

Docker创建redis容器

Docker运行Redis 一&#xff1a;Docker安装Redis docker search redis二&#xff1a;Docker拉取镜像 下面两个命令看自己的需求 docker pull <镜像名称>&#xff1a;<版本号> #需要自己清楚自己需要什么般本的redisdocker pull redis #这个命令会自动下载最新…

C语言入门课程学习笔记3

C语言入门课程学习笔记3 第12课 - if 语句编程练习第13课 - switch 多分支选择语句第14课 - 程序中的循环结构第15课 - while 语句编程练习第16课 - do...while 与 for第17课 - break 与 continue 本文学习自狄泰软件学院 唐佐林老师的 C语言入门课程&#xff0c;图片全部来源于…

BUUCTF-Misc21

[GXYCTF2019]SXMgdGhpcyBiYXNlPw1 1.打开附件 是一个文本文档 里面有很多字符串 2.PuzzleSolver 用PuzzleSolver工具进行多组base64解码 3.得到flag 间谍启示录1 1.打开附件 是一个.iso文件 2.foremost 用foremost 分离文件 查看分离的文件 发现一个压缩包 3.运行 解压之…

Python | Leetcode Python题解之第47题全排列II

题目&#xff1a; 题解&#xff1a; class Solution:def permuteUnique(self, nums: List[int]) -> List[List[int]]:def dfs(x):if x len(nums) - 1:res.append(list(nums)) # 添加排列方案returndic set()for i in range(x, len(nums)):if nums[i] in dic: continue …

历史遗留问题-Oracle 19c RAC 安装时节点连接性问题

测试服务器的二节点数据库宕掉了&#xff0c;原因不明&#xff0c;需要产环境重新安装。我想上次在自己虚拟机安装实验过一次&#xff0c;应该一天能搞定&#xff0c;事实证明&#xff0c;你永远有学不完的bug&#xff01;&#xff01;&#xff01;&#xff01; 首先查看一下系…

算法基础:并查集详解

并查集 并查集&#xff0c;在一些有N个元素的集合应用问题中&#xff0c;我们通常是在开始时让每个元素构成一个单元素的集合&#xff0c;然后按一定顺序将属于同一组的元素所在的集合合并&#xff0c;其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学…

Web前端开发之HTML_2

HTML5简介与基础骨架标题标签标签之段落、换行、水平线标签之图片标签之超文本链接标签之文本列表标签之有序列表列表标签之无序列表 1. HTML5简介与基础骨架 1.1 HTML5简介 HTML5是用来描述网页的一种语言&#xff0c;被称为超文本标记语言。用HTML5编写的文件&#xff0c;后…

伴游平台搭建重点,会用到哪些三方服务?

伴游平台搭建的重点在于确保用户的安全与体验&#xff0c;提供便捷的服务&#xff0c;同时维护平台的稳定运营。在搭建过程中&#xff0c;可能会用到以下三方服务&#xff1a; 身份验证与背景调查服务&#xff1a;由于伴游服务涉及到用户的个人安全和信任问题&#xff0c;因此需…

企业微信代开发应用登录操作

首先声明&#xff1a;企微的文档写得真烂&#xff01;&#xff01;&#xff01;有一些问题&#xff0c;官方情愿在问答区给用户一个个解答&#xff0c;也不愿意在文档写清楚&#xff0c;生怕自己工作量不饱和被优化。 概念说明 代开发应用&#xff0c;是相对于自建应用来说的。…

如何解决 IntelliJ IDEA 2024 启动总闪退问题?一站式解决方案!

&#x1f9e0; 如何解决 IntelliJ IDEA 2024 启动总闪退问题&#xff1f;一站式解决方案&#xff01; 文章目录 &#x1f9e0; 如何解决 IntelliJ IDEA 2024 启动总闪退问题&#xff1f;一站式解决方案&#xff01;摘要引言正文一级标题&#xff1a;检查和优化内存设置一级标题…

经验丰富也被裁了,失业快2年找不到工作?

前几天徐工说&#xff0c;他有个邻居&#xff0c;最近逮到他总是要跟他扯上几句。 原因是徐工一直是做嵌入式开发&#xff0c;而他一直做纯软件开发&#xff0c;具体不知道做后端还是前端。 他说&#xff0c;他至少有半年没上班了&#xff0c;之前在一家龙头物流公司上班。 碰上…

五年Python从业者,谈谈Python的一些优缺点

前言 Python它是作为年轻的血液&#xff0c;融入到编程语言这个大家庭里面&#xff0c;作为具有年轻人的蓬勃朝气的python&#xff0c;那它同时就会有年轻人的桀骜焦躁。 今天就来谈谈Python的一些优缺点。 先从优点说起&#xff0c;我是把它分为5部分。 1.简单————Pyth…

2024最新版JavaScript逆向爬虫教程-------基础篇之深入JavaScript运行原理以及内存管理

目录 一、JavaScript运行原理1.1 前端需要掌握的三大技术1.2 为什么要学习JavaScript1.3 浏览器的工作原理1.4 浏览器的内核1.5 浏览器渲染过程1.6 认识JavaScript引擎1.7 V8引擎以及JavaScript的执行过程1.8 V8引擎执行过程 二、JavaScript的执行过程2.1 初始化全局对象2.2 执…

【vue功能】多张图片合并

多张图片合并成一张图片 步骤一&#xff0c;多张图片上传步骤二&#xff0c;循环获取所有绘制图片的总高度new FileReader()方法作用new Image()方法作用介绍 步骤三&#xff0c;合并多张图片canvas.toDataURL()作用-dpr作用 步骤四&#xff0c;下载图片 步骤一&#xff0c;多张…

深入Linux下的GCC编译器:从入门到精通

目录标题 1、GCC编译器概述2、安装GCC3、GCC的基本使用4、高级功能4.1 多文件编译4.2 静态和动态链接4.3 什么是链接&#xff1f;4.4 静态链接优点缺点 4.5 动态链接优点缺点 4.6 实际应用4.7 编译优化 GCC&#xff08;GNU Compiler Collection&#xff09;是一款免费、开源的编…

从 Android 恢复已删除文件的 3 种简单方法

如何从 Android 恢复已删除的文件&#xff1f;毫不犹豫&#xff0c;有些人可能会认为从 Google 备份恢复 Android 文件太容易了。但是&#xff0c;如果删除的文件未同步到您的帐户或未备份怎么办&#xff1f;您错误的恢复可能会永久删除您想要的数据。因此&#xff0c;我们发布…