zoukankan      html  css  js  c++  java
  • File API文件操作之FileReader二

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

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

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

    思路:

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

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

    效果:

      

    那么话不多说:

    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; 500px">
            <div style=" 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; 300px; height: 300px; border: 2px dotted sienna"></div>
            </div>
        </div>
        <div style="display: inline-block; 200px;height:200px;vertical-align:buttom;border: 1px solid cadetblue;overflow: hidden;position:relative">
            <img  draggable="false" style="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; 200px; height: 200px; border: 2px dotted sienna"></div> -->
    </body>
    <script src="./js/readAsDataURL.js"></script>
    
    </html>

     js代码:

    const IMAGE_MAX_SIZE = 2
    const CUTTER_WIDTH = CUTTER_HEIGHT = 300
    
    class 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

  • 相关阅读:
    数据库基础(2)
    数据库基础
    多线程(3)
    多线程(2)
    多线程(1)
    并发编程(3)
    软件工程——个人总结
    软件工程第二次作业-结对编程
    软件工程第二次作业——结对编程心得体会
    软件工程第一次作业补充
  • 原文地址:https://www.cnblogs.com/cloud-/p/6478045.html
Copyright © 2011-2022 走看看