• 纯前端实现保存表单数据功能


    最近在用管理后台配置数据时,发现辛辛苦苦配置好的表单无缘无故地被覆盖,之后了解到由于我们都是在同一台开发机上做开发,难免会遇到其他同学做数据变更时覆盖掉自己的配置数据。于是我决定在表单配置里增加一项“配置操作”功能来解放自己双手以及惠及他人。

    用什么方式保存?

    1. 找后端同学去帮忙做保存?
    2. 把配置数据都保存到 localStorage?
    3. 把配置数据都保存到本地文本?

    然而看到后端同学繁忙的景象之下,默默地放弃了,所以忽略第一点。如果把数据都保存到 localStorage,那么我是不是还要做一个界面来管理这个配置数据的版本呢,而且还可以选中某个版本快速还原,但这些都需要一定的工作量,localStorage 的数据也不方便导出给别的同学。如果我只用前端技术直接把配置文件保存到本地,那前面两个问题都不存在了,还会带来一个好处就是:拿到这些文件,发布到现网时我可以直接导入,而后端同学只需要运行创建表文件和上传相关的java文件就足够了,减少后端同学的工作量。

    实现方式

    回想时以前做过的一个需求:当用户点击链接时是下载一个PDF文件,而不是直接使用自带的PDF阅读器打开。

    使用a标签的download属性(Chrome和FF已支持),如:

    <a href="/uploadfolder/lalala.pdf" download="filename.pdf">点击下载</a>
    

    这明显需要服务器来支持。我们知道href属性可以是一个链接,也可以是一个锚点、伪协议。

    但也可以是blobURI、dataURI、fileURI

    如果要实现前端保存文本,那么使用dataURI即可实现。
    dataURI 的语法结构如下:

    data:[<mediatype>][;base64],<data>
    

    如果想了解更多关于data URI的知识,可以点击这里

    下载指定的文本的需求就可以快速实现了:

    <a href="data:text/plain,text_text_text_text" download="filename.txt">点击下载</a>
    

    如果想通过调用的方式来触发,需要稍微封装:

    function downloadText (fileName, textCtx) {
    	var aTag;
    		
    	if (fileName && textCtx) {
    	    aTag = document.createElement('a');
    	    aTag.setAttribute('href', 'data:text/plain,' + textCtx);
    	    aTag.setAttribute('download',  fileName);
    	    aTag.click();
        }
    }
    

    虽然管理后台不需要支持IE,但这里顺便扯一下IE,IE要达到该效果需要借助execCommand

    基本思路是创建一个隐藏iframe并添加到页面上,把需要保存的内容写到iframe内并调起iframe的execCommand命令来保存页面。

    var ifr = document.createElement('iframe');
    
    ifr.style.display = 'none';
    document.body.appendChild(ifr);
    ifr.contentWindow.document.write(textCtx);
    ifr.contentWindow.document.execCommand('SaveAs', false, fileName);
    document.body.removeChild(ifr);
    

    如果你想了解更多关于IE下的execCommand,可以点击这里

    整理上述:

    function downloadText (fileName, textCtx) {
    	var aTag, ifr;
    
    	if (fileName && textCtx) {
            if (!~navigator.userAgent.indexOf('MSIE')) {
    	        aTag = document.createElement('a');
    	        aTag.setAttribute('href', 'data:text/plain,' + textCtx);
    	        aTag.setAttribute('download',  fileName);
    	        aTag.click();
            } else {
                ifr = document.createElement('iframe');
                ifr.style.display = 'none';
                document.body.appendChild(ifr);
                ifr.contentWindow.document.write(textCtx); 
                ifr.contentWindow.document.execCommand('SaveAs', false, fileName);
                document.body.removeChild(ifr);
            }
        }
    }
    //let's go 
    downloadText('lala.txt', 'dolemifaso');
    

    关于读取

    使用FileReader可以快速实现,基本思路是 input -> onchange -> new FileReader() -> onload -> readAsDataURL

    关于FileRader和相关例子, 可以点击这里

    关于发送

    这里使用了FormDataXMLHttpRequest
    如果你想了解更多关于FormData, 可以点击这里

    function postForm (formData) {
        var separator, postTarget, rKV, oForm, oReq, keyVals;
    
        if (formData && ~formData.indexOf(separator)) {
            separator = '____|____'; //每个字段的链接符,如: 'a:1____|____b:{"c":"d"}'
            postTarget = 'http://test.com/update.do';
            rKV = /([^:]+):([sS]+)/;
            oForm = new FormData();
            oReq = new XMLHttpRequest();
            keyVals = formData.split(separator); //切割为 [a:1, b:{"c":"d"}]
    
            keyVals.forEach(function (keyVal) {
                    var pairs = keyVal.match(rKV);
    
    			    if (pairs) {
                        oForm.append(pairs[1], pairs[2]);
                    }
    		});
    
            //here we go
            oReq.open("POST", postTarget);
            oReq.send(oForm);
            oReq.onload = function (data) {
                var resText, resData;
    
                if (data.target.status === 200
                    && data.target.readyState === 4) {
                    resText = data.target.responseText;
                    resData = JSON.parse(resText);
    
                    if (resData.retcode === 0) {
                        alert('导入配置成功');
                    } else {
                        alert('导入配置失败:' + resText);
                    }
                }
            }
        } else {
            alert('文件格式不合法');
        }
    }
    

    全文完

  • 相关阅读:
    python-IO编程
    DNS解析流程
    python-模块
    HTTP协议
    python-函数式编程
    nmap扫描结果的6种端口状态
    python-高级特性
    python-函数
    python-基础
    上传之路
  • 原文地址:https://www.cnblogs.com/zzbo/p/5905835.html
Copyright © 2020-2023  润新知