File API文件操作之FileReader二

小编 2026-06-05 阅读:523 评论:0
上一篇说了FileAPI中FileReader的readAsText,这里继续上文,说说另外一个...

上一篇说了FileAPI中FileReader的readAsText,这里继续上文,说说另外一个API readAsDataURL。

这个接口是将File或者Blob读成base64格式的字符串,然后直接挂在HTML5的元素上,例如img就可以直接使用。

实际用途可以是图片预览和图片剪裁,这里我将用来实现图片剪裁。

思路:

1. file api的FileReader实现本地图片预览  

2. 用web api的拖拽功能来实现剪裁

 

效果:

File API文件操作之FileReader二

  

那么话不多说:

html代码:

<html><head>    <title>FileReader 之 readAsDataURL</title></head><body style="margin: 2em 4em"  draggable="false">    <div>图片剪裁</div>    <input type="file" id="fileImageCut" value="选择图片"><br/>    <div  draggable="false" id="imgWrapper" id="container1" style="display: inline-block;width: 500px">        <div style="width: 404px;height: 404px;border:1px solid cornflowerblue;position: relative">            <img draggable="false" style="position: absolute;left:-1px;bottom:-1px; border:1px solid greenyellow " id="imgPreview" />            <div draggable="true" id="cutter" style="position: absolute;cursor:crosshair;left:-px;bottom:-2px; width:300px; height: 300px; border: 2px dotted sienna"></div>        </div>    </div>    <div style="display: inline-block;width: 200px;height:200px;vertical-align:buttom;border: 1px solid cadetblue;overflow: hidden;position:relative">        <img  draggable="false" style="width:266.7px;height:266.7px;position: absolute;left: 0;bottom: 0" id="imgResult">    </div>    <!--<div draggable="true" id="cutter" style="position: absolute;cursor:crosshair;left:62px;top:274px; width:200px; height: 200px; border: 2px dotted sienna"></div> --></body><script src="./js/readAsDataURL.js"></script></html>

 js代码:

const IMAGE_MAX_SIZE = 2const CUTTER_WIDTH = CUTTER_HEIGHT = 300class SimpleImageCutter {    constructor(options) {        this.fileUpload = options.fileUpload        this.imgPreview = options.imgPreview        this.imgResult = options.imgResult        this.cutter = options.cutter        this.percentage = this.imgResult.parentElement.clientWidth / this.cutter.clientWidth        this.iLeft = this.iRight = this.iTop = this.iBottom = null    }    init() {        this.resgiterEvents()    }    resgiterEvents() {        let cLeft, cRight, cTop, cBottom, cOffsetX, cOffsetY,            cutter = this.cutter, imgPreview = this.imgPreview, cBorderWidth = Number.parseInt(cutter.style.borderWidth.replace('px', '')),            cPBorderWidth = Number.parseInt(imgPreview.style.borderWidth.replace('px', ''))        this.fileUpload.addEventListener('change', (ev) => {            let files = ev.target.files, file;            //检查图片类型            if (files.length && (file = files[0])) {                if (!this.checkFile(file)) {                    return                }                //重置高宽                imgPreview.removeAttribute('height')                imgPreview.removeAttribute('width')                imgPreview.style.width = imgPreview.style.height = null                imgPreview.style.visibility = 'hidden'                let fr = new FileReader()                fr.onload = () => {                    imgPreview.onload = () => {                        this.resizeImage()                        imgPreview.style.visibility = 'visible'                        this.resizeCutter()                        this.refreshPercentage()                        this.resizeResult()                        //计算图片相对浏览器的限值                        this.iLeft = imgPreview.getBoundingClientRect().left + document.documentElement.scrollLeft + cPBorderWidth                        this.iTop = imgPreview.getBoundingClientRect().top + document.documentElement.scrollTop + cPBorderWidth                        this.iRight = this.iLeft + imgPreview.clientWidth                        this.iBottom = this.iTop + imgPreview.clientHeight                    }                    this.imgResult.src = imgPreview.src = fr.result                }                //如果错误,抛出异常                fr.onerror = ev => alert(ev.target.error)                                fr.readAsDataURL(file)            }        }, false)        cutter.addEventListener('dragstart', ev => {            cOffsetX = ev.offsetX            cOffsetY = ev.offsetY            /*            let dragIcon = document.createElement("img")             dragIcon.src = 'image/drag.jpg'            dragIcon.width = cutter.width              document.body.appendChild(dragIcon)             ev.dataTransfer.setDragImage(dragIcon, 0, 0); */            //cutter.style.border = "2px red solid"               console.log('dragstart')            return false        }, false)        cutter.addEventListener('dragover', ev => {            //ev.stopPropagation()            //ev.preventDefault()            console.log('dragover')            return false        }, false)        cutter.addEventListener('dragleave', ev => {            //ev.stopPropagation()            //ev.preventDefault()            console.log('dragleave')            return false        }, false)        cutter.addEventListener('drop', ev => {            console.log('drop')        }, false)        cutter.addEventListener('dragend', ev => {            cLeft = ev.clientX - cOffsetX - cBorderWidth            cTop = ev.clientY - cOffsetY - cBorderWidth            cRight = cLeft + cutter.clientWidth + cBorderWidth            cBottom = cTop + cutter.clientHeight + cBorderWidth            if (!this.iTop || cTop < this.iTop || cLeft < this.iLeft || cRight > this.iRight || cBottom > this.iBottom) {                ev.stopPropagation()                ev.preventDefault()            } else {                cutter.style.left = (cLeft - this.iLeft) + 'px'                cutter.style.top =  (cTop - this.iTop) + 'px'                imgResult.style.left = -((cLeft - this.iLeft) * this.percentage).toFixed(2) + 'px'                imgResult.style.top = -((cTop - this.iTop) * this.percentage).toFixed(2) + 'px'            }        }, false)    }    checkFile(file) {        if (!file.type.startsWith("image")) {            alert('不是有效的图片')            return false        }        if (file.size > IMAGE_MAX_SIZE * 1024 * 1024) {            alert(`上传的图片不允许大于${IMAGE_MAX_SIZE}M`)            return false        }        return true    }    resizeImage() {        let img = this.imgPreview, h = img.height, w = img.width,            ph = img.parentElement.clientHeight, pw = img.parentElement.clientWidth,            phc = h / ph, pwc = w / pw        phc > pwc ? img.height = ph : img.width = pw    }    resizeCutter() {        let minValue = Math.min(Math.min(imgPreview.clientHeight, CUTTER_HEIGHT), Math.min(imgPreview.clientWidth, CUTTER_WIDTH))        cutter.style.height = cutter.style.width = minValue + 'px'        cutter.style.top = cutter.style.left = null    }    resizeResult() {        imgResult.style.width = (imgPreview.clientWidth * this.percentage).toFixed(2) + 'px'        imgResult.style.height = (imgPreview.clientHeight * this.percentage).toFixed(2) + 'px'        imgResult.style.top = imgResult.style.left = null    }    refreshPercentage() {        this.percentage = this.imgResult.parentElement.clientWidth / this.cutter.clientWidth    }}(new SimpleImageCutter({    fileUpload: fileImageCut,    imgPreview: imgPreview,    imgResult: imgResult,    cutter: cutter})).init()

 

这种简单实现存在的问题(下一种思路 html5 canvas):

1. 拖动效果体验比较差

2. 剪裁后的图片保存问题

源码路径:https://github.com/xiangwenhu/BlogCodes

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
标签列表