基于Vue的验证码实现
一、验证码核心实现
创建slide-verify.vue,代码如下:
<template><divclass="slide-verify":style="{ width: w + 'px' }"id="slideVerify"onselectstart="return false;"><!-- 图片加载遮蔽罩 --><div :class="{ 'slider-verify-loading': loadBlock }"></div><canvas :width="w" :height="h" ref="canvas"></canvas><div v-if="show" @click="refresh" class="slide-verify-refresh-icon"></div><canvas:width="w":height="h"ref="block"class="slide-verify-block"></canvas><!-- container --><divclass="slide-verify-slider":class="{'container-active': containerActive,'container-success': containerSuccess,'container-fail': containerFail}"><div class="slide-verify-slider-mask" :style="{ width: sliderMaskWidth }"><!-- slider --><div@mousedown="sliderDown"@touchstart="touchStartEvent"@touchmove="handleMoveEvent($event, 'touch')"@touchend="handleMoveEndEvent($event, 'touch')"class="slide-verify-slider-mask-item":style="{ left: sliderLeft }"><div class="slide-verify-slider-mask-item-icon"></div></div></div><span class="slide-verify-slider-text">{{ sliderText }}</span></div></div>
</template>
<script>
const PI = Math.PI;function sum(x, y) {return x + y;
}function square(x) {return x * x;
}
export default {name: "SlideVerify",props: {// block lengthl: {type: Number,default: 42},// block radiusr: {type: Number,default: 10},// canvas widthw: {type: Number,default: 310},// canvas heighth: {type: Number,default: 155},sliderText: {type: String,default: "Slide filled right"},accuracy: {type: Number,default: 5 // 若为 -1 则不进行机器判断},show: {type: Boolean,default: true},imgs: {type: Array,default: () => []}},data() {return {containerActive: false, // container active classcontainerSuccess: false, // container success classcontainerFail: false, // container fail classcanvasCtx: null,blockCtx: null,block: null,block_x: undefined, // container random positionblock_y: undefined,L: this.l + this.r * 2 + 3, // block real lengthimg: undefined,originX: undefined,originY: undefined,isMouseDown: false,trail: [],sliderLeft: 0, // block right offsetsliderMaskWidth: 0, // mask width,success: false, // Bug Fixes 修复了验证成功后还能滑动loadBlock: true, // Features 图片加载提示,防止图片没加载完就开始验证timestamp: null};},mounted() {this.init();},methods: {init() {this.initDom();this.initImg();this.bindEvents();},initDom() {this.block = this.$refs.block;this.canvasCtx = this.$refs.canvas.getContext("2d");this.blockCtx = this.block.getContext("2d");},initImg() {const img = this.createImg(() => {// 图片加载完关闭遮蔽罩this.loadBlock = false;this.drawBlock();this.canvasCtx.drawImage(img, 0, 0, this.w, this.h);this.blockCtx.drawImage(img, 0, 0, this.w, this.h);let { block_x: x, block_y: y, r, L } = this;let _y = y - r * 2 - 1;let ImageData = this.blockCtx.getImageData(x, _y, L, L);this.block.width = L;this.blockCtx.putImageData(ImageData, 0, _y);});this.img = img;},drawBlock() {this.block_x = this.getRandomNumberByRange(this.L + 10,this.w - (this.L + 10));this.block_y = this.getRandomNumberByRange(10 + this.r * 2,this.h - (this.L + 10));this.draw(this.canvasCtx, this.block_x, this.block_y, "fill");this.draw(this.blockCtx, this.block_x, this.block_y, "clip");},draw(ctx, x, y, operation) {let { l, r } = this;ctx.beginPath();ctx.moveTo(x, y);ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI);ctx.lineTo(x + l, y);ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI);ctx.lineTo(x + l, y + l);ctx.lineTo(x, y + l);ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true);ctx.lineTo(x, y);ctx.lineWidth = 2;ctx.fillStyle = "rgba(255, 255, 255, 0.7)";ctx.strokeStyle = "rgba(255, 255, 255, 0.7)";ctx.stroke();ctx[operation]();// Bug Fixes 修复了火狐和ie显示问题ctx.globalCompositeOperation = "destination-over";},createImg(onload) {const img = document.createElement("img");img.crossOrigin = "Anonymous";img.onload = onload;img.onerror = () => {img.src = this.getRandomImg();};img.src = this.getRandomImg();return img;},// 随机生成img srcgetRandomImg() {// return require('../assets/img.jpg')const len = this.imgs.length;return len > 0? this.imgs[this.getRandomNumberByRange(0, len - 1)]: // "https://bing.ioliu.cn/v1/rand?w=300&h=150";"https://source.unsplash.com/300x150/?book,library";// "https://api.dujin.org/pic/fengjing";},getRandomNumberByRange(start, end) {return Math.round(Math.random() * (end - start) + start);},refresh() {this.reset();this.$emit("refresh");},sliderDown(event) {if (this.success) return;this.originX = event.clientX;this.originY = event.clientY;this.isMouseDown = true;this.timestamp = +new Date();},touchStartEvent(e) {if (this.success) return;e.preventDefault();this.originX = e.changedTouches[0].pageX;this.originY = e.changedTouches[0].pageY;this.isMouseDown = true;this.timestamp = +new Date();},bindEvents() {document.addEventListener("mousemove", this.handleMoveEvent);document.addEventListener("mouseup", this.handleMoveEndEvent);},// 处理函数抽离handleMoveEvent: throttle(function(e, type = "mouse") {if (!this.isMouseDown) return false;const moveX =type === "mouse"? e.clientX - this.originX: e.changedTouches[0].pageX - this.originX;const moveY =type === "mouse"? e.clientY - this.originY: e.changedTouches[0].pageY - this.originY;if (moveX < 0 || moveX + 38 >= this.w) return false;this.sliderLeft = moveX + "px";let blockLeft = ((this.w - 40 - 20) / (this.w - 40)) * moveX;this.block.style.left = blockLeft + "px";this.containerActive = true; // add activethis.sliderMaskWidth = moveX + "px";this.trail.push(moveY);}),handleMoveEndEvent(e, type = "mouse") {if (!this.isMouseDown) return false;this.isMouseDown = false;if ((type === "mouse" && e.clientX === this.originX) ||(type === "touch" && e.changedTouches[0].pageX === this.originX))return false;this.containerActive = false; // remove activethis.timestamp = +new Date() - this.timestamp;const { spliced, TuringTest } = this.verify();if (spliced) {if (this.accuracy === -1) {this.containerSuccess = true;this.success = true;this.$emit("success", this.timestamp);return;}if (TuringTest) {// succthis.containerSuccess = true;this.success = true;this.$emit("success", this.timestamp);} else {this.containerFail = true;this.$emit("again");}} else {this.containerFail = true;this.$emit("fail");setTimeout(() => {this.reset();}, 1000);}},verify() {const arr = this.trail; // drag y move distanceconst average = arr.reduce(sum) / arr.length; // averageconst deviations = arr.map(x => x - average); // deviation arrayconst stddev = Math.sqrt(deviations.map(square).reduce(sum) / arr.length); // standard deviationconst left = parseInt(this.block.style.left);const accuracy =this.accuracy <= 1 ? 1 : this.accuracy > 10 ? 10 : this.accuracy;return {spliced: Math.abs(left - this.block_x) <= accuracy,TuringTest: average !== stddev // equal => not person operate};},reset() {this.success = false;this.containerActive = false;this.containerSuccess = false;this.containerFail = false;this.sliderLeft = 0;this.block.style.left = 0;this.sliderMaskWidth = 0;// canvaslet { w, h } = this;this.canvasCtx.clearRect(0, 0, w, h);this.blockCtx.clearRect(0, 0, w, h);this.block.width = w;// generate imgthis.img.src = this.getRandomImg();this.$emit("fulfilled");}},destroyed() {document.removeEventListener("mousemove", this.handleMoveEvent);document.removeEventListener("mouseup", this.handleMoveEndEvent);}
};function throttle(fn,interval = 50,options = { leading: true, trailing: true }
) {const { leading, trailing, resultCallback } = options;let lastTime = 0;let timer = null;const _throttle = function(...args) {return new Promise((resolve, reject) => {const nowTime = new Date().getTime();if (!lastTime && !leading) lastTime = nowTime;const remainTime = interval - (nowTime - lastTime);if (remainTime <= 0) {if (timer) {clearTimeout(timer);timer = null;}const result = fn.apply(this, args);if (resultCallback) resultCallback(result);resolve(result);lastTime = nowTime;return;}if (trailing && !timer) {timer = setTimeout(() => {timer = null;lastTime = !leading ? 0 : new Date().getTime();const result = fn.apply(this, args);if (resultCallback) resultCallback(result);resolve(result);}, remainTime);}});};_throttle.cancel = function() {if (timer) clearTimeout(timer);timer = null;lastTime = 0;};return _throttle;
}
</script>
<style scoped>
.slide-verify {position: relative;
}/* 图片加载样式 */
.slider-verify-loading {position: absolute;top: 0;right: 0;left: 0;bottom: 0;background: rgba(255, 255, 255, 0.9);z-index: 999;animation: loading 1.5s infinite;
}@keyframes loading {0% {opacity: 0.7;}100% {opacity: 9;}
}.slide-verify-block {position: absolute;left: 0;top: 0;
}.slide-verify-refresh-icon {position: absolute;right: 0;top: 0;width: 34px;height: 34px;cursor: pointer;background: url("../assets/icon_light.png") 0 -437px;background-size: 34px 471px;
}.slide-verify-slider {position: relative;text-align: center;width: 100%;height: 40px;line-height: 40px;margin-top: 15px;background: #f7f9fa;color: #45494c;border: 1px solid #e4e7eb;
}.slide-verify-slider-mask {position: absolute;left: 0;top: 0;height: 40px;border: 0 solid #1991fa;background: #d1e9fe;
}.slide-verify-slider-mask-item {position: absolute;top: 0;left: 0;width: 40px;height: 40px;background: #fff;box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);cursor: pointer;transition: background 0.2s linear;
}.slide-verify-slider-mask-item:hover {background: #1991fa;
}.slide-verify-slider-mask-item:hover .slide-verify-slider-mask-item-icon {background-position: 0 -13px;
}.slide-verify-slider-mask-item-icon {position: absolute;top: 15px;left: 13px;width: 14px;height: 12px;background: url("../assets/icon_light.png") 0 -26px;background-size: 34px 471px;
}
.container-active .slide-verify-slider-mask-item {height: 38px;top: -1px;border: 1px solid #1991fa;
}.container-active .slide-verify-slider-mask {height: 38px;border-width: 1px;
}.container-success .slide-verify-slider-mask-item {height: 38px;top: -1px;border: 1px solid #52ccba;background-color: #52ccba !important;
}.container-success .slide-verify-slider-mask {height: 38px;border: 1px solid #52ccba;background-color: #d2f4ef;
}.container-success .slide-verify-slider-mask-item-icon {background-position: 0 0 !important;
}.container-fail .slide-verify-slider-mask-item {height: 38px;top: -1px;border: 1px solid #f57a7a;background-color: #f57a7a !important;
}.container-fail .slide-verify-slider-mask {height: 38px;border: 1px solid #f57a7a;background-color: #fce1e1;
}.container-fail .slide-verify-slider-mask-item-icon {top: 14px;background-position: 0 -82px !important;
}.container-active .slide-verify-slider-text,
.container-success .slide-verify-slider-text,
.container-fail .slide-verify-slider-text {display: none;
}
</style>
基于slide-verify.vue创建组件,index.js代码如下:
import SlideVerify from './slide-verify.vue'const plugins = {install(Vue) {Vue.component(SlideVerify.name, SlideVerify)}
}if (typeof window !== 'undefined' && window.Vue) {window.Vue.use(SlideVerify)
}export default plugins
二、在项目中使用验证码
在main.js中应用:
import { createApp } from 'vue'
import App from './App.vue'
// 导入验证码
import SlideVerify from './xxx/index'const vue = createApp(App)
vue.use(SlideVerify) // 在vue中使用
vue.mount('#app')
准备验证码图片:
其中icon_light.png图标图片如下,其他img.jpg图片可以是任意图片。
在vue中使用验证码,App.vue代码如下:
<template><div id="app"><slide-verify ref="slideBlock" @success="onSuccess" @again="onAgain" @fulfilled="onFulfilled" @fail="onFail"@refresh="onRefresh" :slider-text="text" :imgs="imgs" :accuracy="accuracy"></slide-verify><div>{{ msg }}</div><button class="btn" @click="handleClick">在父组件点击刷新</button></div>
</template><script setup>
import img0 from './assets/img.jpg';
import img1 from './assets/img1.jpg';
import img2 from './assets/img2.jpg';
import img3 from './assets/img3.jpg';
import img4 from './assets/img4.jpg';
import img5 from './assets/img5.jpg';
import {ref} from "vue";const slideBlock = ref();
const msg = ref('');
const text = ref('向右滑动->');
const imgs = ref([img0,img1,img2,img3,img4,img5,
]);
const accuracy = ref(1); // 精确度小,可允许的误差范围小;为1时,则表示滑块要与凹槽完全重叠,才能验证成功。默认值为5const onSuccess = (times) => {console.log('验证通过');msg.value = `login success, 耗时${(times / 1000).toFixed(1)}s`;
};
const onFail = () => {console.log('验证不通过');msg.value = ''
};
const onRefresh = () => {console.log('点击了刷新小图标');msg.value = ''
};
const onFulfilled = () => {console.log('刷新成功啦!');
};
const onAgain = () => {console.log('检测到非人为操作的哦!');msg.value = 'try again';// 刷新handleClick();
};
const handleClick = () => {slideBlock.value.reset();msg.value = ''
}</script><style scoped>
#app {font-family: 'Avenir', Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;color: #2c3e50;margin-top: 60px;
}.btn {margin-top: 20px;outline: 0;border: none;padding: 8px 15px;border-radius: 5px;color: #fff;background-color: #1890ff;cursor: pointer;
}.btn:active {box-shadow: 1px 5px 0 rgba(0, 0, 0, 0.1) inset;
}
</style>
运行项目查看:
相关文章:

基于Vue的验证码实现
一、验证码核心实现 创建slide-verify.vue,代码如下: <template><divclass"slide-verify":style"{ width: w px }"id"slideVerify"onselectstart"return false;"><!-- 图片加载遮蔽罩 -->&…...
P4【力扣217,389,496】【数据结构】【哈希表】C++版
【217】存在重复元素 给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。 示例 1: 输入:nums [1,2,3,1] 输出:true 示例 2:…...

PE文件(六)新增节-添加代码作业
一.手动新增节添加代码 1.当预备条件都满足,节表结尾没有相关数据时: 现在我们将ipmsg.exe用winhex打开,在节的最后新增一个节用于存放我们要增加的数据 注意:飞鸽的文件对齐和内存对齐是一致的 先判断节表末尾到第一个节之间…...

ICRA 2024: NVIDIA 联合多伦多大学、加州大学伯克利分校、苏黎世联邦理工学院等研究人员开发了精细操作的手术机器人
英伟达(NVIDIA)正与学术研究人员合作,研究手术机器人。 NVIDIA 联合多伦多大学、加州大学伯克利分校、苏黎世联邦理工学院和佐治亚理工学院的研究人员开发了 ORBIT-Surgical,一个训练机器人的模拟框架,可以提高手术团…...
探索Go语言的原子操作秘籍:sync/atomic.Value全解析
引言 在并发编程的世界里,数据的一致性和线程安全是永恒的话题。Go语言以其独特的并发模型——goroutine和channel,简化了并发编程的复杂性。然而,在某些场景下,我们仍然需要一种机制来保证操作的原子性。这就是sync/atomic.V…...
【java深入学习第3章】利用 Spring Boot 和 Screw 快速生成数据库设计文档
免费多模型AI网站,支持豆包、GPT-4o、谷歌Gemini等AI模型,无限制使用,快去白嫖👉海鲸AI🔥🔥🔥 在开发过程中,数据库设计文档是非常重要的,它可以帮助开发者理解数据库结构࿰…...

继“三级淋巴结”之后,再看看“单细胞”如何与AI结合【医学AI|顶刊速递|05-25】
小罗碎碎念 24-05-25文献速递 今天想和大家分享的是肿瘤治疗领域的另一个热点——单细胞技术,我们一起来看看,最新出炉的顶刊,是如何把AI与单细胞结合起来的。 另外,今天是周末,所以会有两篇文章——一篇文献速递&…...

[图解]产品经理创新之阿布思考法
0 00:00:00,000 --> 00:00:01,900 那刚才我们讲到了 1 00:00:02,730 --> 00:00:03,746 业务序列图 2 00:00:03,746 --> 00:00:04,560 然后怎么 3 00:00:05,530 --> 00:00:06,963 画现状,怎么改进 4 00:00:06,963 --> 00:00:09,012 然后改进的模式…...

Proteus仿真小技巧(隔空连线)
用了好几天Proteus了.总结一下使用的小技巧. 目录 一.隔空连线 1.打开添加网络标号 2.输入网络标号 二.常用元件 三.运行仿真 四.总结 一.隔空连线 引出一条线,并在末尾点一下. 1.打开添加网络标号 选择添加网络标号, 也可以先点击按钮,再去选择线(注意不要点端口) 2.…...

抖音极速版:抖音轻量精简版本,新人享大福利
和快手一样,抖音也有自己的极速版,可视作抖音的轻量精简版,更专注于刷视频看广告赚钱,收益比抖音要高,可玩性更佳。 抖音极速版简介 抖音极速版是一个提供短视频创业和收益任务的平台,用户可以通过观看广…...

leetCode-hot100-数组专题之双指针
数组双指针专题 1.同向双指针1.1例题26.删除有序数组中的重复项27.移除元素80.删除有序数组中的重复项 Ⅱ 2.相向双指针2.1例题11.盛最多水的容器42.接雨水581.最短无序连续子数组 双指针在算法题中很常见,下面总结双指针在数组中的一些应用,主要分为两类…...

完成商品SPU管理页面
文章目录 1.引入前端界面1.将前端界面放到commodity下2.创建菜单3.进入前端项目,使用npm添加依赖1.根目录下输入2.报错 chromedriver2.27.2的问题3.点击链接下载压缩包,然后使用下面的命令安装4.再次安装 pubsub-js 成功5.在main.js中引入这个组件 4.修改…...

Ansible实战YAML语言完成apache的部署,配置,启动全过程
🏡作者主页:点击! 🏝️Ansible专栏:点击! ⏰️创作时间:2024年5月24日15点59分 目录 💯趣站推荐💯 🎊前言 ✨️YAML语言回顾 🎆1.编写YAML文…...
深入探索微软Edge:新一代浏览器的演进与创新
在数字时代的浪潮中,浏览器已不再只是简单的网页访问工具,而是成为了连接信息、服务与用户之间的重要桥梁。微软Edge作为微软公司推出的一款全新的浏览器,不仅承载着微软在互联网领域的最新愿景,还融合了多项前沿技术,…...
k8s使用Volcano调度gpu
k8s部署 https://www.yangxingzhen.com/9817.html cri-dockerd安装 https://zhuanlan.zhihu.com/p/632861515 安装nvidia-container-runtime https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html 安装k8s-device-plugin https://…...
x的平方根-力扣
本题想到使用二分法不断逼近一个区间,直到最后趋近于x,从而求得解。注意的点,一开始使用 if(mid * mid < x) 进行判断时,会出现越界,原因是输入一个很大的数是,超过int表示的范围,继而修改为…...

hot100 -- 回溯(上)
目录 🍞科普 🌼全排列 AC DFS 🚩子集 AC DFS 🎂电话号码的字母组合 AC DFS 🌼组合总和 AC DFS 🍞科普 忘记 dfs 的,先看看这个👇 DFS(深度优先搜索…...
5.24数据库作业
考虑如下关系模式R(A,B.C.D,E,F)上的函数依赖集F: {A→BCD,BC→DE,B→D,D→A} 1、计算B的闭包。 2、(使用Armstrong公理)证明AF是超码。 3、计算上述函数依赖集F的正则覆盖;给出你的推导的步骤并解释。 4、基于正则覆盖࿰…...

go-zero 实战(5)
引入Prometheus 用 Prometheus 监控应用 1. 用 docker 启动 Prometheus 编辑配置位置,我将 prometheus.yaml 和 targets.json 文件放在了 /opt/prometheus/conf目录下 prometheus.yaml global:scrape_interval: 15s # 抓取间隔evaluation_interval: 15s # 评估…...

Python异常处理:打造你的代码防弹衣!
Hi,我是阿佑,上文咱们讲到——揭秘Python的魔法:装饰器的超能力大揭秘 ♂️✨,阿佑将带领大家通过精准捕获异常、使用with语句和上下文管理器、以及异常链等高级技巧来增强代码的健壮性。就像为代码穿上防弹衣,保护它…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...