前端打工人必看:Axios搞定Excel导出上传,拒绝加班还能准时干饭

前端打工人必看:Axios搞定Excel导出上传,拒绝加班还能准时干饭
前端打工人必看:Axios搞定Excel导出上传,拒绝加班还能准时干饭
兄弟们,是不是每次产品提"导出个Excel"或者"批量上传"就头大?别慌,今天不整那些虚头巴脑的理论,直接上干货,聊聊怎么用Axios把这俩硬骨头啃下来。想想以前为了个文件下载,后端甩锅前端,前端甩锅浏览器,最后还得自己含泪填坑的日子,是不是血压都上来了?
说实话,我刚入行那会儿,听到"文件上传下载"这五个字就腿软。看着后端老哥甩过来一句"你直接用axios就行",我特么以为真的就一行代码的事儿。结果?下载下来的Excel打不开,上传的图片变成乱码,跨域报错红得跟灯笼似的… 踩过的坑能填平太平洋。今天就把这些血泪史摊开了说,争取让你看完就能去产品面前装个大的,准时下班干饭。
这玩意儿到底是个啥
Axios这老伙计大家都不陌生,但处理二进制流这块儿,好多新人容易懵圈。我当年也是,以为axios.get()万能,结果碰到文件流直接傻眼。
简单说,上传就是把文件塞进FormData里像寄快递一样打包发走。下载呢,就是告诉服务器"我要的是流",然后浏览器得知道怎么把这堆二进制数据变成能打开的.xls或.xlsx文件。别被什么MIME类型、Blob对象吓到,其实逻辑跟咱们点外卖差不多——接单、打包、配送、签收。
先说说Blob这玩意儿是啥。Blob全称Binary Large Object,翻译过来就是"二进制大对象"。听起来高大上,其实就是浏览器用来存二进制数据的一个容器。你可以把它想象成一个虚拟的文件,存在内存里,用完了得手动清理,不然就像家里堆满了外卖盒,迟早要出事。
还有FormData,这货是HTML5新增的API,专门用来模拟表单提交。为啥要用它?因为传统的JSON传不了文件啊!你试试把一张图片转成base64塞JSON里,那体积直接爆炸,服务器看了都想打人。
这里有个坑我得提前说:很多人以为文件上传必须用POST,其实PUT也行,PATCH也行,甚至GET理论上也能传(虽然有点变态)。但大部分场景下,POST是最稳妥的,后端对接的时候也最省心。
上传文件那点破事
核心就是FormData,这玩意儿就是个虚拟的表单,能把文件和普通字段混在一起塞进去。记得把Content-Type设成multipart/form-data吗?其实Axios会自动帮你搞,手贱去设反而容易翻车。
基础版:单文件上传
最朴素的上传长这样,但朴素不代表能用:
// 别急着复制,这是反面教材版本constuploadFile=(file)=>{const formData =newFormData(); formData.append('file', file);// 手贱手动设置Content-Type,结果 boundary 丢了,后端直接懵逼 axios.post('/api/upload', formData,{headers:{'Content-Type':'multipart/form-data'// 大错特错!}});};看到上面那个注释了吗?这就是新手常犯的错。FormData的boundary(边界符)是浏览器自动生成的,你手动设置Content-Type会把boundary覆盖掉,后端解析的时候就找不到文件从哪开始、到哪结束,直接报Missing boundary或者Invalid boundary的错误。
正确的姿势是让Axios自己处理,或者如果你用了拦截器统一设置headers,记得在上传请求里删掉Content-Type:
// 这才是能跑起来的版本constuploadFile=async(file)=>{const formData =newFormData();// 第一个参数是字段名,要跟后端约定好,别瞎写 formData.append('file', file);// 还可以塞点其他数据,比如用户ID、业务类型啥的 formData.append('userId','9527'); formData.append('bizType','avatar');try{const response =await axios.post('/api/upload', formData,{// 这里啥也不用设,Axios看到FormData会自动搞Content-Type// 但如果你全局拦截器加了Content-Type,得在这里覆盖掉headers:{'Content-Type':undefined// 让浏览器自己发挥}}); console.log('上传成功:', response.data);return response.data;}catch(error){ console.error('上传翻车:', error);throw error;}};进阶版:多文件上传
多文件上传其实就是循环往FormData里append,没啥高科技,别想太复杂。但这里有个细节:同一个字段名塞多个文件,后端能不能接住要看人家用的什么框架。
// 多文件上传,后端是Node.js + multer 或者 Java + SpringBoot 的情况constuploadMultipleFiles=async(fileList)=>{const formData =newFormData();// 方法1:同一个字段名塞多个,后端用数组接收 fileList.forEach((file, index)=>{// 字段名都叫files,后端接收 files[] formData.append('files', file);// 如果想保留原始文件名信息,可以额外传 formData.append(`fileNames[${index}]`, file.name);});// 方法2:不同字段名,适合每个文件有不同业务含义的场景// formData.append('idCard', fileList[0]);// formData.append('bankCard', fileList[1]);try{const response =await axios.post('/api/upload/batch', formData,{headers:{'Content-Type':undefined}});return response.data;}catch(error){ console.error('批量上传失败:', error);throw error;}};高阶版:带进度条的上传
大文件上传怎么办?总不能让用户对着进度条发呆半小时吧,得搞个上传进度监听,让用户知道还没死机。Axios提供了onUploadProgress回调,这个API底层用的是XMLHttpRequest的progress事件。
constuploadWithProgress=(file, onProgress)=>{const formData =newFormData(); formData.append('file', file);return axios.post('/api/upload', formData,{headers:{'Content-Type':undefined},// 关键配置:上传进度回调onUploadProgress:(progressEvent)=>{// progressEvent里有loaded和total,单位是字节const percentCompleted = Math.round((progressEvent.loaded *100)/ progressEvent.total ); console.log(`上传进度: ${percentCompleted}%`);// 把进度抛给外部,用来更新UIif(onProgress){onProgress(percentCompleted);}},// 大文件记得调大超时时间,或者设0不限制timeout:0});};// 在React组件里用constFileUploadComponent=()=>{const[progress, setProgress]=useState(0);const[uploading, setUploading]=useState(false);consthandleUpload=async(file)=>{setUploading(true);setProgress(0);try{awaituploadWithProgress(file,(percent)=>{setProgress(percent);}); message.success('上传成功!');}catch(error){ message.error('上传失败,请重试');}finally{setUploading(false);}};return(<div><Upload beforeUpload={handleUpload} fileList={[]}><Button icon={<UploadOutlined />} loading={uploading}> 点击上传 </Button></Upload>{uploading &&<Progress percent={progress} status="active"/>}</div>);};防手贱:防抖处理
上传的时候加个防抖,防止用户手残狂点按钮,瞬间发起几百个请求把服务器打挂。这玩意儿在测试环境可能没事,上了生产要是被压测或者恶意点击,直接P0事故。
import{ debounce }from'lodash';// 封装一个带防抖的上传函数const debouncedUpload =debounce(async(file, callback)=>{try{const result =awaituploadWithProgress(file, callback);return result;}catch(error){ console.error(error);}},300,{leading:true,trailing:false});// 首次点击立即执行,后面300ms内的点击忽略// 或者更粗暴点,直接在上传期间禁用按钮constUploadButton=()=>{const[isUploading, setIsUploading]=useState(false);consthandleClick=async()=>{if(isUploading)return;// 简单粗暴但有效setIsUploading(true);try{awaituploadFile(selectedFile);}finally{setIsUploading(false);}};return<Button loading={isUploading} onClick={handleClick}>上传</Button>;};下载文件才是真·深水区
重点来了!请求头里必须加responseType: 'blob',不然你拿到的就是一堆乱码字符串,神仙也救不了。这坑我踩过不止一次,后端明明返回的是二进制流,我打印response.data一看,满屏的������,当时就想砸键盘。
最简版:基础下载
// 错误的示范,千万别这么写constwrongDownload=async()=>{const res =await axios.get('/api/download/excel');// res.data 是一堆乱码字符串,因为axios默认把响应当JSON解析了 console.log(res.data);// "������..."};// 正确的打开方式constdownloadExcel=async()=>{try{const response =awaitaxios({url:'/api/export/user-list',method:'GET',responseType:'blob',// 关键!告诉Axios我要二进制流params:{startDate:'2024-01-01',endDate:'2024-12-31'}});// 现在response.data是个Blob对象const blob =newBlob([response.data],{type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});// 造个临时链接const url = window.URL.createObjectURL(blob);// 创建隐藏的a标签const link = document.createElement('a'); link.href = url; link.download ='用户列表.xlsx';// 指定下载文件名 document.body.appendChild(link);// 触发点击 link.click();// 清理现场,这步很重要! document.body.removeChild(link); window.URL.revokeObjectURL(url);}catch(error){ console.error('下载失败:', error);}};文件名怎么搞?
上面那个例子文件名是写死的,实际项目中肯定要从后端拿。后端通常在Content-Disposition里藏了个小秘密,格式大概是attachment; filename="xxx.xlsx"或者attachment; filename*=UTF-8''xxx.xlsx(后者是为了支持中文文件名)。
constdownloadWithFileName=async()=>{const response =awaitaxios({url:'/api/export/report',method:'POST',responseType:'blob',data:{reportType:'monthly'}});// 从响应头里抠文件名const contentDisposition = response.headers['content-disposition'];let fileName ='下载文件.xlsx';// 给个默认值if(contentDisposition){// 先尝试匹配 filename*="UTF-8''xxx" 这种格式(RFC 5987)const utf8Match = contentDisposition.match(/filename\*=UTF-8''([^;]+)/i);if(utf8Match && utf8Match[1]){// 需要decodeURIComponent,因为中文被编码了 fileName =decodeURIComponent(utf8Match[1]);}else{// 再尝试普通的 filename="xxx"const normalMatch = contentDisposition.match(/filename="([^"]+)"/i);if(normalMatch && normalMatch[1]){ fileName = normalMatch[1];}}}const blob =newBlob([response.data],{type: response.headers['content-type']});const url = window.URL.createObjectURL(blob);const link = document.createElement('a'); link.href = url; link.download = fileName; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url);};这里有个坑要注意:如果后端没配置暴露Content-Disposition头,你前端是读不到的!axios的response.headers里会没有这个字段。这时候得让后端在CORS配置里加Access-Control-Expose-Headers: Content-Disposition。
封装一个通用的下载函数
把创建a标签、清理URL这些脏活累活全包了,以后调用就一行代码。这种工具函数一定要提前写好,别等到项目里到处都是复制粘贴的下载代码,改起来想死。
/** * 通用文件下载函数 * @param {string} url - 下载地址 * @param {object} config - axios配置 * @param {string} defaultName - 默认文件名 */exportconst downloadFile =async(url, config ={}, defaultName ='download')=>{try{const response =awaitaxios({ url,method:'GET',responseType:'blob',...config });// 提取文件名const contentDisposition = response.headers['content-disposition'];let fileName = defaultName;if(contentDisposition){const match = contentDisposition.match(/filename\*?=(?:UTF-8'')?([^;]+)/i);if(match){ fileName =decodeURIComponent(match[1].replace(/['"]/g,''));}}// 创建下载链接const blob =newBlob([response.data],{type: response.headers['content-type']||'application/octet-stream'});const downloadUrl = window.URL.createObjectURL(blob);const link = document.createElement('a'); link.href = downloadUrl; link.download = fileName; link.style.display ='none'; document.body.appendChild(link); link.click();// 延迟清理,确保下载已经开始setTimeout(()=>{ document.body.removeChild(link); window.URL.revokeObjectURL(downloadUrl);},100);return{success:true, fileName };}catch(error){ console.error('下载失败:', error);// 如果后端返回的是JSON错误信息(比如权限不足),需要特殊处理if(error.response && error.response.data instanceofBlob){const text =await error.response.data.text();try{const errorData =JSON.parse(text);thrownewError(errorData.message ||'下载失败');}catch{thrownewError('下载失败');}}throw error;}};// 使用示例,一行代码搞定downloadFile('/api/export/users',{params:{dept:'tech'}},'用户列表.xlsx');带下载进度的大文件下载
上传有进度条,下载当然也可以有。不过下载的进度回调叫onDownloadProgress,用法一模一样。
constdownloadLargeFile=async(url, fileName, onProgress)=>{const response =awaitaxios({ url,method:'GET',responseType:'blob',onDownloadProgress:(progressEvent)=>{if(progressEvent.total){const percent = Math.round((progressEvent.loaded *100)/ progressEvent.total); onProgress?.(percent);}},timeout:0// 大文件不设超时});// 保存文件const blob =newBlob([response.data]);const downloadUrl = window.URL.createObjectURL(blob);const link = document.createElement('a'); link.href = downloadUrl; link.download = fileName; link.click(); window.URL.revokeObjectURL(downloadUrl);};// 在组件里用,加个进度条constDownloadButton=()=>{const[progress, setProgress]=useState(0);const[downloading, setDownloading]=useState(false);consthandleDownload=async()=>{setDownloading(true);setProgress(0);try{awaitdownloadLargeFile('/api/export/big-data','大数据报表.xlsx',(percent)=>setProgress(percent));}catch(error){ message.error('下载失败');}finally{setDownloading(false);}};return(<div><Button onClick={handleDownload} loading={downloading}> 下载大文件 </Button>{downloading &&<Progress percent={progress}/>}</div>);};咱得客观聊聊这方案
优点嘛,Axios生态好,拦截器用起来爽,统一处理错误和Token方便得一匹。但缺点也不是没有,咱得实话实说。
优点
1. 拦截器真香
可以在请求发送前统一加Token,响应回来后统一处理错误,文件下载上传也能享受到这个便利。
// 请求拦截器:自动加Token axios.interceptors.request.use(config=>{const token = localStorage.getItem('token');if(token){ config.headers.Authorization =`Bearer ${token}`;}return config;});// 响应拦截器:统一处理401 axios.interceptors.response.use(response=> response,error=>{if(error.response?.status ===401){// Token过期,踢去登录页 window.location.href ='/login';}return Promise.reject(error);});2. 错误处理统一
文件下载的时候,如果后端返回401或者500,你拿到的是个Blob,需要特殊处理才能读到错误信息。这个逻辑可以封装在拦截器里:
axios.interceptors.response.use(asyncresponse=>{// 如果是文件下载请求,且状态不对,尝试解析错误信息if(response.config.responseType ==='blob'&& response.status !==200){const text =await response.data.text();try{const error =JSON.parse(text);return Promise.reject(error);}catch{return Promise.reject(newError('下载失败'));}}return response;},error=> Promise.reject(error));缺点
1. 大文件内存爆炸
前面说的Blob下载,是把整个文件塞进内存的。如果你要下载几个G的日志文件,浏览器直接卡死。这时候得用流式下载或者后端直接返回下载链接,让浏览器自己去下。
2. 兼容性坑
虽然现在IE都进博物馆了,但有些老旧安卓机上的WebView还是偶尔抽风,得留个心眼。特别是URL.createObjectURL和URL.revokeObjectURL,在部分WebView里可能有内存泄漏问题。
3. 无法暂停续传
Axios本身不支持断点续传,如果要实现暂停、继续功能,得用更底层的XMLHttpRequest或者专门的库比如resumablejs。
真实项目里怎么落地
光讲代码不讲场景就是耍流氓,说说我在实际项目里遇到的几个典型场景。
场景一:报表导出(异步生成)
后台管理系统里的报表导出,数据量通常很大,不可能点一下立马下完。通常配合定时任务,用户点一下,后端生成好了再通知前端去拉,别傻等。
// 流程:点击导出 -> 后端返回任务ID -> 轮询任务状态 -> 完成后下载constexportReport=async(params)=>{// 1. 发起导出任务const{data:{ taskId }}=await axios.post('/api/export/task', params);// 2. 轮询任务状态constcheckStatus=()=>newPromise((resolve, reject)=>{const timer =setInterval(async()=>{try{const{ data }=await axios.get(`/api/export/task/${taskId}/status`);if(data.status ==='completed'){clearInterval(timer);resolve(data.downloadUrl);}elseif(data.status ==='failed'){clearInterval(timer);reject(newError('生成失败'));}// 还在处理中,继续等}catch(error){clearInterval(timer);reject(error);}},2000);// 每2秒查一次});try{const downloadUrl =awaitcheckStatus();// 3. 下载文件awaitdownloadFile(downloadUrl,{},'报表.xlsx');}catch(error){ message.error(error.message);}};场景二:批量导入+实时预览
批量导入用户数据,上传完立马解析预览,错了哪行高亮显示,这种体验才叫丝滑。
constUploadWithPreview=()=>{const[previewData, setPreviewData]=useState([]);const[errorRows, setErrorRows]=useState([]);consthandleUpload=async(file)=>{const formData =newFormData(); formData.append('file', file);// 先上传到预览接口,不真正入库const{ data }=await axios.post('/api/import/preview', formData,{headers:{'Content-Type':undefined}});setPreviewData(data.list);setErrorRows(data.errors);// 错误行号if(data.errors.length >0){ message.warning(`发现${data.errors.length}行错误,请修改后重新上传`);}};constconfirmImport=async()=>{// 确认无误后,真正导入await axios.post('/api/import/confirm',{data: previewData }); message.success('导入成功');};return(<div><Upload beforeUpload={handleUpload} fileList={[]}><Button>上传Excel预览</Button></Upload>{previewData.length >0&&(<><Table dataSource={previewData} rowClassName={(record, index)=> errorRows.includes(index)?'error-row':''}/><Button type="primary" onClick={confirmImport}> 确认导入 </Button></>)}</div>);};场景三:图片压缩上传
图片或者附件上传,记得做本地压缩和格式校验,别等传到服务器报错了再让用户重传,那是友尽的节奏。
import Compressor from'compressorjs';constcompressAndUpload=(file)=>{// 先校验if(!['image/jpeg','image/png'].includes(file.type)){ message.error('只支持jpg/png格式');return;}if(file.size >10*1024*1024){ message.error('图片不能超过10MB');return;}// 压缩newCompressor(file,{quality:0.6,// 压缩质量maxWidth:1920,// 最大宽度maxHeight:1080,success(result){// result是压缩后的Blob,转成File再上传const compressedFile =newFile([result], file.name,{type: result.type,lastModified: Date.now()});uploadFile(compressedFile);},error(err){ message.error('压缩失败');}});};遇到报错别只会重启
最常见就是下载下来文件打不开,99%是responseType没设对,或者后端返回的不是流而是JSON报错信息,得先判断一下。
下载下来是乱码或打不开
// 排查步骤1:检查responseType axios.get('/api/download',{responseType:'blob'})// 排查步骤2:检查后端是否真的返回了流// 有时候后端出错了,返回的是JSON错误信息,但Content-Type还是application/json// 这时候你强行转Blob,下载下来就是个包含错误信息的文本文件// 安全做法:先判断一下是不是真的BlobconstsafeDownload=async()=>{const response =await axios.get('/api/download',{responseType:'blob',// 这个配置很重要,让axios把原始响应透传过来,不要自动转换transformResponse:[]});// 检查Content-Typeconst contentType = response.headers['content-type'];if(contentType.includes('application/json')){// 后端返回的是JSON,可能是错误信息const text =await response.data.text();const error =JSON.parse(text);thrownewError(error.message);}// 确定是文件流,继续下载流程// ...};跨域问题
OPTIONS预检请求要是挂了,文件根本发不出去,赶紧找后端查CORS配置。文件上传的CORS配置要特别注意:
Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With Access-Control-Expose-Headers: Content-Disposition # 这个必须加,否则前端读不到文件名 超时问题
大文件上传下载一定要把timeout调大点,或者干脆设成0无限等待(当然最好还是做进度条)。
// 针对不同接口设置不同超时const api = axios.create({baseURL:'/api',timeout:10000// 默认10秒});// 上传接口超时设长点 api.post('/upload', formData,{timeout:300000});// 5分钟// 下载接口根据文件大小动态设置 api.get('/download/big-file',{responseType:'blob',timeout:0// 不限制});几个让同事喊666的骚操作
1. 全局上传下载管理器
搞个全局的上传下载管理器,显示所有进行中的任务,暂停、取消功能安排上,逼格满满。
// 用Context或者Redux管理全局状态constDownloadManager=()=>{const[tasks, setTasks]=useState([]);constaddTask=(url, fileName)=>{const taskId = Date.now();const newTask ={id: taskId, fileName,progress:0,status:'pending',// pending, downloading, completed, errorcontroller:newAbortController()// 用于取消请求};setTasks(prev=>[...prev, newTask]);// 开始下载axios({ url,responseType:'blob',signal: newTask.controller.signal,// 绑定取消信号onDownloadProgress:(e)=>{const percent = Math.round((e.loaded *100)/ e.total);updateTaskProgress(taskId, percent);}}).then(response=>{// 保存文件...updateTaskStatus(taskId,'completed');}).catch(error=>{if(error.name ==='CanceledError'){updateTaskStatus(taskId,'cancelled');}else{updateTaskStatus(taskId,'error');}});return taskId;};constcancelTask=(taskId)=>{const task = tasks.find(t=> t.id === taskId);if(task && task.controller){ task.controller.abort();// 取消请求}};return(<div className="download-manager">{tasks.map(task=>(<div key={task.id} className="task-item"><span>{task.fileName}</span><Progress percent={task.progress}/>{task.status ==='downloading'&&(<Button onClick={()=>cancelTask(task.id)}>取消</Button>)}</div>))}</div>);};2. 利用拦截器统一处理
// 请求拦截器:给所有上传请求加特定标识 axios.interceptors.request.use(config=>{if(config.data instanceofFormData){ config.headers['X-Upload-Request']='true';// 上传请求不设置超时,或者设置很长 config.timeout =0;}return config;});// 响应拦截器:统一提取下载文件名 axios.interceptors.response.use(response=>{if(response.config.responseType ==='blob'){const disposition = response.headers['content-disposition'];if(disposition){// 把文件名挂到response上,方便业务代码取用 response.fileName =extractFileName(disposition);}}return response;});3. 文件类型校验工具函数
constFILE_TYPES={'image':['image/jpeg','image/png','image/gif'],'excel':['application/vnd.ms-excel','application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],'word':['application/msword','application/vnd.openxmlformats-officedocument.wordprocessingml.document']};constvalidateFile=(file, type, maxSize =10*1024*1024)=>{const errors =[];if(!FILE_TYPES[type].includes(file.type)){ errors.push(`文件类型错误,请上传${type}格式文件`);}if(file.size > maxSize){ errors.push(`文件大小不能超过${maxSize /1024/1024}MB`);}return{valid: errors.length ===0, errors };};// 使用const{ valid, errors }=validateFile(file,'excel',5*1024*1024);if(!valid){ message.error(errors.join(','));}最后扯点闲篇
技术这东西,有时候真不是越新越好,Axios这老家伙在文件处理上依然稳如老狗。我见过太多项目为了追求"新技术",明明Axios能搞定的事,非要上什么GraphQL、grpc-web,结果文件上传这块儿折腾得死去活来。
别光收藏不吃灰,赶紧去项目里试两把,万一明天产品经理就提了这个需求呢?到时候你能淡定地说"这个简单,半天搞定",而不是"我研究研究",那逼格完全不一样。
要是真踩了坑也别骂街,毕竟咱们前端就是在填坑和造坑之间反复横跳,痛并快乐着嘛。我到现在还记得第一次成功导出Excel时的那种成就感,虽然代码写得像屎山,但能用啊!后来重构了七八遍,现在回头看第一版的代码,简直想穿越回去抽自己两巴掌。
行了,不多哔哔,我去补个觉,昨晚为了修这个导出bug熬到三点,头发又掉了一把。你们要是试的过程中遇到啥奇葩问题,欢迎在群里吐槽,咱们一起研究。记住,能准时干饭的前端才是好前端,共勉!
欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
推荐:DTcode7的博客首页。
一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身农奴把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟!
| 专栏系列(点击解锁) | 学习路线(点击解锁) | 知识定位 |
|---|---|---|
| 《微信小程序相关博客》 | 持续更新中~ | 结合微信官方原生框架、uniapp等小程序框架,记录请求、封装、tabbar、UI组件的学习记录和使用技巧等 |
| 《AIGC相关博客》 | 持续更新中~ | AIGC、AI生产力工具的介绍,例如stable diffusion这种的AI绘画工具安装、使用、技巧等总结 |
| 《HTML网站开发相关》 | 《前端基础入门三大核心之html相关博客》 | 前端基础入门三大核心之html板块的内容,入坑前端或者辅助学习的必看知识 |
| 《前端基础入门三大核心之JS相关博客》 | 前端JS是JavaScript语言在网页开发中的应用,负责实现交互效果和动态内容。它与HTML和CSS并称前端三剑客,共同构建用户界面。 通过操作DOM元素、响应事件、发起网络请求等,JS使页面能够响应用户行为,实现数据动态展示和页面流畅跳转,是现代Web开发的核心 | |
| 《前端基础入门三大核心之CSS相关博客》 | 介绍前端开发中遇到的CSS疑问和各种奇妙的CSS语法,同时收集精美的CSS效果代码,用来丰富你的web网页 | |
| 《canvas绘图相关博客》 | Canvas是HTML5中用于绘制图形的元素,通过JavaScript及其提供的绘图API,开发者可以在网页上绘制出各种复杂的图形、动画和图像效果。Canvas提供了高度的灵活性和控制力,使得前端绘图技术更加丰富和多样化 | |
| 《Vue实战相关博客》 | 持续更新中~ | 详细总结了常用UI库elementUI的使用技巧以及Vue的学习之旅 |
| 《python相关博客》 | 持续更新中~ | Python,简洁易学的编程语言,强大到足以应对各种应用场景,是编程新手的理想选择,也是专业人士的得力工具 |
| 《sql数据库相关博客》 | 持续更新中~ | SQL数据库:高效管理数据的利器,学会SQL,轻松驾驭结构化数据,解锁数据分析与挖掘的无限可能 |
| 《算法系列相关博客》 | 持续更新中~ | 算法与数据结构学习总结,通过JS来编写处理复杂有趣的算法问题,提升你的技术思维 |
| 《IT信息技术相关博客》 | 持续更新中~ | 作为信息化人员所需要掌握的底层技术,涉及软件开发、网络建设、系统维护等领域的知识 |
| 《信息化人员基础技能知识相关博客》 | 无论你是开发、产品、实施、经理,只要是从事信息化相关行业的人员,都应该掌握这些信息化的基础知识,可以不精通但是一定要了解,避免日常工作中贻笑大方 | |
| 《信息化技能面试宝典相关博客》 | 涉及信息化相关工作基础知识和面试技巧,提升自我能力与面试通过率,扩展知识面 | |
| 《前端开发习惯与小技巧相关博客》 | 持续更新中~ | 罗列常用的开发工具使用技巧,如 Vscode快捷键操作、Git、CMD、游览器控制台等 |
| 《photoshop相关博客》 | 持续更新中~ | 基础的PS学习记录,含括PPI与DPI、物理像素dp、逻辑像素dip、矢量图和位图以及帧动画等的学习总结 |
| 日常开发&办公&生产【实用工具】分享相关博客》 | 持续更新中~ | 分享介绍各种开发中、工作中、个人生产以及学习上的工具,丰富阅历,给大家提供处理事情的更多角度,学习了解更多的便利工具,如Fiddler抓包、办公快捷键、虚拟机VMware等工具 |
吾辈才疏学浅,摹写之作,恐有瑕疵。望诸君海涵赐教。望轻喷,嘤嘤嘤
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。愿斯文对汝有所裨益,纵其简陋未及渊博,亦足以略尽绵薄之力。倘若尚存阙漏,敬请不吝斧正,俾便精进!
