vue中-iview的upload上传图片-获取本地图片绝对路径-在前端实现图片预览

在用iview的upload上传图片的时候,想要实现图片的预览。 但是在iview给的例子中,是每上传一个图片触发一次上传事件,调一次接口,后台将图片存入数据库,再回传给前端,这样实现图片在前端的显示。这个方法对于上传多张图片,无疑很不现实。 于是就有了下面的方法。 想要实现上传多张图片,上传的图依次显示出来,点击提交,实现同时上传,只调一次接口,后台一次性将多张图片存入数据库。 在图片上传前 'handleBeforeUpload' 事件中加入以下代码,获取的_base64即为本地图片的绝对路径,将其存起来,在赋值到img的src路径,即可实现图片在上传前的显示,实现图片的预览 const reader = new FileReader() reader.readAsDataURL(file) reader.onload = () => { const _base64 = reader.result console.log(_base64) } 整体代码copy //图片上传前事件 handleBeforeUpload (file) { this.file = file //需要传给后台的file文件 const reader = new FileReader() reader.readAsDataURL(file) reader.onload = () => { const _base64 = reader.result this.imgUrl = _base64 //将_base64赋值给图片的src,实现图片预览 } return false//阻止图片继续上传,使得form表单提交时统一上传 }

June 10, 2019 · 1 min · jiezi

关于vue项目中移动端实现用户选择照片照片裁剪一次上传多张图片仿微信发朋友圈功能

关于vue项目中移动端实现用户选择照片、照片裁剪、一次上传多张图片功能(仿微信发朋友圈)。最终要实现的效果如下图所示: 涉及的功能有1、图片的选择2、图片从手机相机选择、拍照3、图片选择后的裁剪4、图片在页面的显示效果5、图片的删除6、base64图片转化为file类型的文件7、图片的上传 首先安装cropperjs 和exif-js 裁剪依赖这两个包cnpm install --save cropperjs exif-js 图片的上传相关代码 图片从手机相机选择、拍照图片选择后的裁剪 initilize(opt) { let self = this; this.options = opt; //创建dom this.createElement(); this.resultObj = opt.resultObj; //初始化裁剪对象 this.cropper = new Cropper(this.preview, { aspectRatio: opt.aspectWithRatio / opt.aspectHeightRatio, autoCropArea: opt.autoCropArea || 0.8, viewMode: 2, guides: true, cropBoxResizable: true, //是否通过拖动来调整剪裁框的大小 cropBoxMovable: true, //是否通过拖拽来移动剪裁框。 dragCrop: false, dragMode: "move", //‘crop’: 可以产生一个新的裁剪框3 ‘move’: 只可以移动3 ‘none’: 什么也不处理 center: true, zoomable: true, //是否允许放大图像。 zoomOnTouch: true, //是否可以通过拖动触摸来放大图像。 scalable: true, // minCropBoxHeight: 750, // minCropBoxWidth: 750, background: false, checkOrientation: true, checkCrossOrigin: true, zoomable: false, zoomOnWheel: false, center: false, toggleDragModeOnDblclick: false, ready: function() { if (opt.aspectRatio == "Free") { let cropBox = self.cropper.cropBox; cropBox.querySelector("span.cropper-view-box").style.outline = "none"; self.cropper.disable(); } } }); }, //创建一些必要的DOM,用于图片裁剪 createElement() { //初始化图片为空对象 this.preview = null; let str = '<div><img id="clip_image" src="originUrl"></div><button type="button" id="cancel_clip">取消</button><button type="button" id="clip_button">确定</button>'; str += '<div class="crop_loading"><div class="crop_content"><div class="crop_text">图片修剪中...</div></div></div>'; str += '<div class="crop_success"><div class="crop_success_text">上传成功</div></div></div>'; let body = document.getElementsByTagName("body")[0]; this.reagion = document.createElement("div"); this.reagion.id = "clip_container"; this.reagion.className = "container"; this.reagion.innerHTML = str; body.appendChild(this.reagion); this.preview = document.getElementById("clip_image"); //绑定一些方法 this.initFunction(); }, //初始化一些函数绑定 initFunction() { let self = this; this.clickBtn = document.getElementById("clip_button"); this.cancelBtn = document.getElementById("cancel_clip"); //确定事件 this.addEvent(this.clickBtn, "click", function() { self.crop(); }); //取消事件 this.addEvent(this.cancelBtn, "click", function() { self.destoried(); }); //清空input的值 this.addEvent(this.fileObj, "click", function() { this.value = ""; }); }, //外部接口,用于input['file']对象change时的调用 clip(e, opt) { let self = this; this.fileObj = e.srcElement; let files = e.target.files || e.dataTransfer.files; if (!files.length) return false; //不是图片直接返回 //调用初始化方法 this.initilize(opt); //获取图片文件资源 this.picValue = files[0]; //调用方法转成url格式 this.originUrl = this.getObjectURL(this.picValue); //每次替换图片要重新得到新的url if (this.cropper) { this.cropper.replace(this.originUrl); } }, //图片转码方法 getObjectURL(file) { let url = null; if (window.createObjectURL != undefined) { // basic url = window.createObjectURL(file); } else if (window.URL != undefined) { // mozilla(firefox) url = window.URL.createObjectURL(file); } else if (window.webkitURL != undefined) { // webkit or chrome url = window.webkitURL.createObjectURL(file); } return url; }, //点击确定进行裁剪 crop() { let self = this; let image = new Image(); let croppedCanvas; let roundedCanvas; // Crop document.querySelector(".crop_loading").style.display = "block"; setTimeout(function() { croppedCanvas = self.cropper.getCroppedCanvas(); // Round roundedCanvas = self.getRoundedCanvas(croppedCanvas); let imgData = roundedCanvas.toDataURL(); image.src = imgData; //判断图片是否大于100k,不大于直接上传,反之压缩 if (imgData.length < 100 * 1024) { // self.resultObj.src = imgData; //图片上传 self.postImg(imgData); } else { image.onload = function() { //压缩处理 let data = self.compress(image, self.Orientation); // self.resultObj.src = data; //图片上传 self.postImg(data); }; } }, 20); }, //获取裁剪图片资源 getRoundedCanvas(sourceCanvas) { let canvas = document.createElement("canvas"); let context = canvas.getContext("2d"); let width = sourceCanvas.width; let height = sourceCanvas.height; canvas.width = width; canvas.height = height; context.imageSmoothingEnabled = true; context.drawImage(sourceCanvas, 0, 0, width, height); context.globalCompositeOperation = "destination-in"; context.beginPath(); context.rect(0, 0, width, height); context.fill(); return canvas; }, //销毁原来的对象 destoried() { let self = this; //移除事件 this.removeEvent(this.clickBtn, "click", null); this.removeEvent(this.cancelBtn, "click", null); this.removeEvent(this.fileObj, "click", null); //移除裁剪框 this.reagion.parentNode.removeChild(this.reagion); //销毁裁剪对象 this.cropper.destroy(); this.cropper = null; }, //图片上传 postImg(imageData) { console.log(imageData); this.$emit("callback", imageData); //这边写图片的上传 let self = this; self.destoried(); this.imgList.push(imageData); }, //图片旋转 rotateImg(img, direction, canvas) { //最小与最大旋转方向,图片旋转4次后回到原方向 const min_step = 0; const max_step = 3; if (img == null) return; //img的高度和宽度不能在img元素隐藏后获取,否则会出错 let height = img.height; let width = img.width; let step = 2; if (step == null) { step = min_step; } if (direction == "right") { step++; //旋转到原位置,即超过最大值 step > max_step && (step = min_step); } else { step--; step < min_step && (step = max_step); } //旋转角度以弧度值为参数 let degree = (step * 90 * Math.PI) / 180; let ctx = canvas.getContext("2d"); switch (step) { case 0: canvas.width = width; canvas.height = height; ctx.drawImage(img, 0, 0); break; case 1: canvas.width = height; canvas.height = width; ctx.rotate(degree); ctx.drawImage(img, 0, -height); break; case 2: canvas.width = width; canvas.height = height; ctx.rotate(degree); ctx.drawImage(img, -width, -height); break; case 3: canvas.width = height; canvas.height = width; ctx.rotate(degree); ctx.drawImage(img, -width, 0); break; } }, //图片压缩 compress(img, Orientation) { let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); //瓦片canvas let tCanvas = document.createElement("canvas"); let tctx = tCanvas.getContext("2d"); let initSize = img.src.length; let width = img.width; let height = img.height; //如果图片大于四百万像素,计算压缩比并将大小压至400万以下 let ratio; if ((ratio = (width * height) / 4000000) > 1) { console.log("大于400万像素"); ratio = Math.sqrt(ratio); width /= ratio; height /= ratio; } else { ratio = 1; } canvas.width = width; canvas.height = height; // 铺底色 ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, canvas.width, canvas.height); //如果图片像素大于100万则使用瓦片绘制 let count; if ((count = (width * height) / 1000000) > 1) { count = ~~(Math.sqrt(count) + 1); //计算要分成多少块瓦片 // 计算每块瓦片的宽和高 let nw = ~~(width / count); let nh = ~~(height / count); tCanvas.width = nw; tCanvas.height = nh; for (let i = 0; i < count; i++) { for (let j = 0; j < count; j++) { tctx.drawImage( img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh ); ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh); } } } else { ctx.drawImage(img, 0, 0, width, height); } //修复ios上传图片的时候 被旋转的问题 if (Orientation != "" && Orientation != 1) { switch (Orientation) { case 6: //需要顺时针(向左)90度旋转 this.rotateImg(img, "left", canvas); break; case 8: //需要逆时针(向右)90度旋转 this.rotateImg(img, "right", canvas); break; case 3: //需要180度旋转 this.rotateImg(img, "right", canvas); //转两次 this.rotateImg(img, "right", canvas); break; } } //进行最小压缩 let ndata = canvas.toDataURL("image/png", 0.1); console.log("压缩前:" + initSize); console.log("压缩后:" + ndata.length); console.log( "压缩率:" + ~~((100 * (initSize - ndata.length)) / initSize) + "%" ); tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0; return ndata; }, //添加事件 addEvent(obj, type, fn) { if (obj.addEventListener) { obj.addEventListener(type, fn, false); } else { obj.attachEvent("on" + type, fn); } }, //移除事件 removeEvent(obj, type, fn) { if (obj.removeEventListener) { obj.removeEventListener(type, fn, false); } else { obj.detachEvent("on" + type, fn); } }图片在页面的显示效果暂无图片的删除base64图片转化为file类型的文件 bytes = window.atob(this.imgList[i].split(',')[1]); ...

April 25, 2019 · 5 min · jiezi

基于Laravel5.8支持Markdown的开源博客VienBlog

laravel-blogVien Blog - 一款基于laravel5.8开发的,支持markdown编辑以及图片拖拽上传的博客系统、SEO友好博主网站VienBlog这里有些小秘密博客亮点界面简洁、适配pc和mobile、有良好的视觉体验支持markdown、并且可以拖拽或者粘贴上传图片、分屏实时预览SEO友好:支持自定义文章slug、支持meta title、description、keywords自定义导航、自定义sidebar、随时去掉不需要的模块支持标签、分类、置顶、分享、友链等博客基本属性支持AdSense支持百度自动提交链接和手动提交链接博客展示Demo演示地址: 这是一个DEMO后台管理文章列表主要操作有创作、编辑、置顶、删除(软删除)创作和编辑创作和编辑页面Markdown编辑器:支持拖拽粘贴上传图片、预览、全屏、分屏预览前端展示参照 这是一个DEMO看完Demo,如果你觉得还过得去,想要用一用试试呢,赶紧往下看喔。使用博客安装获取源码git clone git@github.com:luvvien/laravel-blog.git进入项目目录后,用composer安装依赖composer install生成.env文件cp .env.example .env创建数据库vienblog ,字符集采用 utf8mb4, utf8mb4_general_ci编辑.env文件 vim .env,修改MySQL数据库连接配置,请将DB_HOST,DB_PORT,DB_USERNAME,DB_PASSWORD 改成你的数据库配置。[…]DB_CONNECTION=mysqlDB_HOST=127.0.0.1DB_PORT=3306DB_DATABASE=vienblogDB_USERNAME=rootDB_PASSWORD=root[…]数据迁移和数据填充php artisan migratephp artisan db:seed创建storage软连接php artisan storage:link设置目录权限chmod -R 755 storage/chown -R www-data:www-data storage/使用可以选择临时预览,也可以用Nginx部署服务临时预览php artisan serv打开浏览器访问127.0.0.1:8000使用NginxNginx配置,将root指向项目的public目录,请用pwd 查看目录,并且改成你目录,千万不要直接粘贴复制。root /app/laravel-blog/public;完整配置server { listen 8088 default_server; listen [::]:8088 default_server; root /apps/vien_blog/public; index index.php index.html index.htm; server_name _; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ .php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php7.2-fpm.sock; # fpm,因为版本不同路径会有区别,这里请改成你,不知道路径可以执行php-fpm便会显示 # fastcgi_pass 127.0.0.1:9000; # cgi }}打开浏览器访问127.0.0.1:8088后台登录地址/admin默认的admin管理账号是vien@byteinf.com密码是vienblog,进入控制台后可以修改管理员信息使用百度自动推送和主动推送请先在config/vienblog.php中按照注释配置相关的信息,自动推送是在网页访问时推送,主动推送执行以下代码会将未提交过的链接提交到百度php artisan push:baidu讨论群QQ群号:149347741 (欢迎开发者,技术爱好者,站长加入)联系我Email: support@vienblog.comLicense使用Vien Blog构建应用,必须在页脚保留Powered by Vien Blog字样以及相关链接在遵守以上规则的情况下,你可以享受等同于MIT License协议的授权。使用Vien Blog并且遵守上述协议的用户可以享受Vien Blog的博客导航,联系我将你的博客地址添加到Vien Blog的网站导航中。 ...

April 6, 2019 · 1 min · jiezi

如何在Github提交图片,做一个自己的图片仓库

因项目需要,出了这个教程,主要是让大家对于将图片/gif等提交的GitHub上,产生一个外网链接的方式。本文为HMStrange项目组的第二个入门任务。接下来按照教程步骤开始吧。一、在Github上选择新建一个项目二、填写项目的信息,这个项目就是HMStrange的图片仓库,接下来的架构图等都会放到这个项目中。所以我将它取名为:img_HMStrange 。大家可以按照自己的风格来取名三、建立项目后,将项目clone到自己本地。四、在自己适合的文件夹下,将项目clone下来,这里有点重复,不过希望大家能看清晰一点。五、准备一张自己的ID(组员昵称)手写签名,然后再项目中新建一个文件夹,将图片存放在这个文件夹中。六、在项目根路径下,打开git bash七、提交项目到GitHub上,这里有两个代码git add .git commit -am 添加个人签名git push八、重新到自己的GitHub项目,刷新一下,看到自己提交的信息,然后找到图片位置 九、点击Download,获取图片在GitHub上的外联地址最后,在需要用到的地方,比如说md的格式,我们可以写上去如下,HMStrange组成员,请将手写签名填写提交到项目上。项目提交的教程按照 Noseparte说: 开源项目HMStrange贡献记,进行提交。最后效果图:请到项目 doc/members/specification.md 填写手写签名图片

April 2, 2019 · 1 min · jiezi

node之本地服务器图片上传

在自己做一个简单的后台管理系统时,用的是node作本地数据库,然后用了Element-ui的upload组件来实现图片的上传,中间有遇到那么点小坑,这里记录下,比较坑的一点就是,不知道文件的命名不能带空格,然后改了好久1.index.vue文件这里的话,就是简单点的使用图形界面框架Element-ui的上传组件,然后,action就是服务器端的地址,我这里使用了代理,将localhost:8080代理到你使用node作为服务器的地址就可以了<template> <div class=“avatar”> <img :src=“avatar?avatar:defaultImg” /> </div> <el-upload class=“upload-demo” drag action=“http://localhost:8080/api/upload” :show-file-list=“false” :on-success=“uploadImgSuccess” > <i class=“el-icon-upload”></i> <div class=“el-upload__text”>将文件拖到此处,或<em>点击上传</em></div> </el-upload></template><script>import defaultImg from ‘@/assets/img/avatar.png’export default{ data() { return { avatar: ’’ } }, methods: { uploadImgSuccess(res) { this.avatar = res.result.url; } }}</script>2.代理文件我这里使用的是vue-cli3脚手架来搭建的项目,所以,自己在项目的根目录下创建一个vue.config.js来做一些配置module.exports = { devServer: { port: 8080, headers: { }, inline: true, overlay: true, stats: ’errors-only’, proxy: { ‘/api’: { target: ‘http://127.0.0.1:3000’, changeOrigin: true // 是否跨域 } } },};3.node服务器端文件这里很重要的一点就是设置静态资源目录app.use(’/serverImage’, express.static(path.join(__dirname, ‘serverImage’)));对图片上传进行了方法的封装const fs = require(‘fs’);const path = require(‘path’);/* formidable用于解析表单数据,特别是文件上传 /const formidable = require(‘formidable’);/ 用于时间格式化 /const formatTime = require(‘silly-datetime’);/ 图片上传 /module.exports = (req, res) => { / 创建上传表单 / let form = new formidable.IncomingForm(); / 设置编码格式 / form.encoding = ‘utf-8’; / 设置上传目录(这个目录必须先创建好) / form.uploadDir = path.join(__dirname, ‘../serverImage’); / 保留文件后缀名 / form.keepExtensions = true; / 设置文件大小 */ form.maxFieldsSize = 2 * 1024 1024; / 格式化form数据 / form.parse(req, (err, fields, files) => { let file = files.file; / 如果出错,则拦截 / if(err) { return res.send({‘status’: 500, msg: ‘服务器内部错误’, result: ‘’}); } if(file.size > form.maxFieldsSize) { fs.unlink(file.path); return res.send({‘status’: -1, ‘msg’: ‘图片不能超过2M’, result: ‘’}); } / 存储后缀名 / let extName = ‘’; switch (file.type) { case ‘image/png’: extName = ‘png’; break; case ‘image/x-png’: extName = ‘png’; break; case ‘image/jpg’: extName = ‘jpg’; break; case ‘image/jpeg’: extName = ‘jpg’; break; } if(extName.length == 0) { return res.send({‘status’: -1, ‘msg’: ‘只支持jpg和png格式图片’, result: ‘’}); } / 拼接新的文件名 / let time = formatTime.format(new Date(), ‘YYYYMMDDHHmmss’); let num = Math.floor(Math.random() * 8999 + 10000); let imageName = ${time}_${num}.${extName}; let newPath = form.uploadDir + ‘/’ + imageName; / 更改名字和路径 / fs.rename(file.path, newPath, (err) => { if(err) { return res.send({‘status’: -1, ‘msg’: ‘图片上传失败’, result: ‘’}); } else { return res.send({‘status’: 200, ‘msg’: ‘图片上传成功’, result: {url: http://localhost:3000/serverImage/${imageName}}}); } }) })};方法的调用const express = require(’express’);const router = express.Router();const uploadImg = require(’./uploadImg’);/ 上传图片 /router.post(’/upload’, (req, res) => { uploadImg(req, res);});module.exports = router;服务器端入口文件const express = require(’express’);const app = express();const path = require(‘path’);/ body-parser是一个HTTP请求体解析的中间件 * 使用这个模块可以解析JSON、Raw、文本、URL-encoded格式的请求体 * /const bodyParser = require(“body-parser”);const dataBaseOperate = require(’./database/operate’);/ 以application/json格式解析数据 /app.use(bodyParser.json());/ 以application/x-www-form-urlencoded格式解析数据 /app.use(bodyParser.urlencoded({ extended: false }));/ 设置静态资源目录 */app.use(’/serverImage’, express.static(path.join(__dirname, ‘serverImage’)));app.use(’/api’, dataBaseOperate);app.listen(3000, () => { console.log(‘server is listening to http://localhost:3000’)});4.小结下对于接口文件的返回,这里使用了body-parser这个中间件来对node返回的body进行json格式的解析很重要的一点就是设置静态资源目录,不然的话就会报错,找不到文件或者文件夹设置静态资源目录,用于存储服务器端的静态资源文件app.use(’/serverImage’, express.static(path.join(__dirname, ‘serverImage’)));然后就是对文件的命名不能出现空格文件的链接可以使用本地服务器端的url地址正在努力学习中,若对你的学习有帮助,留下你的印记呗(点个赞咯^_^)往期好文推荐:判断ios和Android及PC端webpack打包(有面试题)纯css实现瀑布流(multi-column多列及flex布局)实现单行及多行文字超出后加省略号 ...

March 26, 2019 · 2 min · jiezi

用element的upload组件实现多图片上传和压缩

我用vuex做状态管理,七牛云做图床。项目地址:多图片上传组件效果展示项目执行流程首先,让我们来分析一下实现多图片上传的流程:前端向后端请求用来上传图片至服务器的token后端为每张要上传的图片生成一个图片名,并用这个图片名生成token后端将图片名和token返回给前端前端拿到token以后,将图片上传至服务器上传成功以后,前端将图片名发给后端后端将图片名存入数据库项目实现过程1.我们要利用element-ui的Upload组件布置界面://upload.vue<el-upload :action= domain ref=“upload” accept=‘image/jpeg,image/gif,image/png’ :auto-upload=“false” :http-request=“upqiniu” :limit=“limit” :multiple=“multiple” list-type=“picture-card” :before-upload=“beforeUpload” :on-preview=“handlePictureCardPreview” :on-change=“handldChange” :on-remove=“handleRemove”> <i class=“el-icon-plus”></i></el-upload><el-dialog :visible.sync=“dialogVisible”> <img width=“100%” :src=“dialogImageUrl” alt=""></el-dialog>domain 指的是我们的上传地址,upqiniu 是我们自定义的上传方法,beforeUpload 是图片上传前执行的方法。关于该组件的其他用法可以在element的官方文档查阅:Upload 上传2.对图片进行压缩// upload.vueimgQuality: 0.5, //压缩图片的质量dataURItoBlob(dataURI, type) { var binary = atob(dataURI.split(’,’)[1]); var array = []; for(var i = 0; i < binary.length; i++) { array.push(binary.charCodeAt(i)); } return new Blob([new Uint8Array(array)], {type: type});},beforeUpload(param) { //对图片进行压缩 const imgSize = param.size / 1024 / 1024 if(imgSize > 1) { const _this = this return new Promise(resolve => { const reader = new FileReader() const image = new Image() image.onload = (imageEvent) => { const canvas = document.createElement(‘canvas’); const context = canvas.getContext(‘2d’); const width = image.width * _this.imgQuality const height = image.height * _this.imgQuality canvas.width = width; canvas.height = height; context.clearRect(0, 0, width, height); context.drawImage(image, 0, 0, width, height); const dataUrl = canvas.toDataURL(param.type); const blobData = this.dataURItoBlob(dataUrl, param.type); resolve(blobData) } reader.onload = (e => { image.src = e.target.result; }); reader.readAsDataURL(param); }) }}压缩图片实现起来比较简单。就是在beforeUpload()方法里面return一个Promise,Promise里面我们把图片的长度和宽度按比例进行缩小,并把图片画到canvas上,然后把canvas转成一个blod对象。3.前端向后端请求上传token。//upload.vueupqiniu(param) { let filetype = ’’ if (param.file.type === ‘image/png’) { filetype = ‘png’ } else { filetype = ‘jpg’ } const formdata = { filetype: filetype, param: param } this.actionGetUploadToken(formdata) }// vuex/action.jsactionGetUploadToken({commit}, obj) { const msg = { filetype: obj.filetype } usersApi.getImgUploadToken(msg).then((response) => { if(response.stateCode === 200) { commit(‘uploadImg’, {’token’: response.token, ‘key’: response.key, ‘param’: obj.param}) } }, (error) => { console.log(获取图片上传凭证错误:${error}) commit(‘uploadImgError’) })},4.后端生成上传token,并发给前端,我用Python实现。filetype = data.get(‘filetype’)# 构建鉴权对象q = Auth(configs.get(‘qiniu’).get(‘AK’), configs.get(‘qiniu’).get(‘SK’))# 生成图片名salt = ‘’.join(random.sample(string.ascii_letters + string.digits, 8))key = salt + ‘’ + str(int(time.time())) + ‘.’ + filetype# 生成上传 Token,可以指定过期时间等token = q.upload_token(configs.get(‘qiniu’).get(‘bucket_name’), key, 3600)return Response({“stateCode”: 200, “token”: token, “key”: key}, 200)5.前端接收token,开始向服务器上传图片// vuex/state.jsimgName: [], //图片名数组// vuex/mutations.jsuploadImg(state, msg) { const config = { useCdnDomain: true, region: qiniu.region.z2 } var putExtra = { fname: msg.param.file.name, params: {}, mimeType: [“image/png”, “image/jpeg”, “image/gif”] }; var observer = { next(res){ }, error(err){ console.log(图片上传错误信息:${err.message}) }, complete(res){ console.log(图片上传成功:${res.key}) state.imgName.push(res.key) } } var observable = qiniu.upload(msg.param.file, msg.key, msg.token, putExtra, config) //上传开始 var subscription = observable.subscribe(observer)},6.上传成功以后,将图片名存入数据库// 用到upload.vue的界面this.imgsList = this.imgName.map(key => http://${this.qiniuaddr}/${key})switch(this.imgsList.length) { case 4: this.img4 = this.imgsList[3] case 3: this.img3 = this.imgsList[2] case 2: this.img2 = this.imgsList[1] case 1: this.img1 = this.imgsList[0]}let obj = { goods_img1: this.img1, goods_img2:this.img2, goods_img3:this.img3, goods_img4:this.img4}//将信息发送给后端this.actionPublish(obj) ...

February 11, 2019 · 2 min · jiezi

图片上传方案汇总

图片上传是前端开发中经常使用到的,上传方案也有很多种吧,可能你有在使用一些插件完成上传,(比如我以前自己写的一个后台系统)现在在这里总结下图片上传的解决方案。主要有一下几种:1.input 标签之 file 类型2.FileReader 对象:读取文件3.FileReader.readAsDataURL():将读取的文件转换为 base64 编码的字符串4.FormData 对象5.使用 axios 上传input 标签之 file 类型当设置 input 标签 type 为 file 时,input 表现性状为上传文件样式file-input 有如下属性:accept指定选择文件类型的范围。默认为所有文件类型图片为 accept=”image/“文件类型取值见MDNcapture当文件类型为图片或视频且在移动端时,此属性才有意义。capture = ‘user’ 调用前置摄像头capture = ‘environment’ 调用后置摄像头不设置则为用户自己选择multiple一个 Boolean 值,如果存在,则表示用户可以选择多个文件files返回一个 FileList,列出每个所选文件对象。除非 multiple 指定了属性,否则此列表只有一个成员。主要用于 JS 操作。<!– html –><input type=“file” multiple id=“imgLocal” accept=“image/” />// jslet inp = document.querySelector(’#imgLocal’)inp.onchange = function(e) { let fileList = document.querySelector(’#imgLocal’).files console.log(fileList) //files}FileReader 对象我们用 FileReader 对象实现图片预览功能。FileReader 对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。构造函数new FileReader()返回一个新构造的 FileReader。属性FileReader.readyState表示 FileReader 状态的数字,取值如下0:EMPTY/还没有加载任何数据1:LOADING/数据正在被加载2:DONE/已完成全部的读取请求FileReader.result文件的内容。该属性仅在读取操作完成后才有效。FileReader.error事件及方法我们主要是用 FileReader.onload 事件及 FileReader.readAsDataURL() 方法,其他见MDNFileReader.onload处理 load 事件。该事件在读取操作完成时触发FileReader.readAsDataURL()开始读取指定的 Blob 中的内容。一旦完成,result 属性中将包含一个 data: URL 格式的字符串以表示所读取文件的内容。//继续使用上文的fileListlet file = fileList[0]const fileReader = new FileReader()fileReader.readAsDataURL(file) //读取图片fileReader.addEventListener(’load’, function() { // 读取完成 let res = fileReader.result // res是base64格式的图片})我们将 DOM 上 img 的 src 设为读取的结果即可实现预览功能。FormData 对象FormData 对象的使用:1.用一些键值对来模拟一系列表单控件:即把 form 中所有表单元素的 name 与 value 组装成一个 queryString2.异步上传二进制文件。构造函数new FormData()返回一个新构造的 FormData。方法FormData 方法有很多。我们这里只用了她的 append()方法formData.append(name, value, filename)name:属性名value:属性值,在我们这里则指 file 数据filename:当第二个参数为 file 或 blob 时,告诉服务器的文件名。Blob 对象的默认文件名是“blob”。File 对象的默认文件名 是文件的文件名。代码如下:// 继续使用上文的fileconst formDate = new FormData()formDate.append(‘userPicture’, file, ‘1.jpg’)使用 axios 上传大家都知道axios可以做数据请求,也可以实现图片上传的功能,主要是设置 header 中的 Content-Type//继续使用上文的formDatelet config = { headers: { ‘Content-Type’: ‘multipart/form-data’ }}axios .post(‘serverUrl’, formDate, config) .then(res => { console.log(res) }) .catch(err => { console.log(err) })axios 也可以使用onUploadProgress监听上传进度,不再赘述。其他其他还有直接form表单提交文件等方式,可能不太自由。诸位有兴趣的可以看一下。 ...

January 6, 2019 · 1 min · jiezi