现如今,随着浏览器功能的日益强大,为了节省网络资源和增加用户体验,越来越多的数据被存储在客户端。常见的浏览器离线存储数据的方式有Cookie、webStorage、webSQL、indexDB、File system等,常用的cookie只能存储4kb的数据,而localStorage,sessionStorage只能存储2.5M-10M的数据,并且在代码中是同步执行的。

那么如果做可视化大屏或者聊天室这类应用,我们想在客户端存储大量数据,应该怎么做呢?

可以用到的技术有 WebSQL(官方已不再维护,现代浏览仍然保留其功能,仅作了解) 和 indexDB(支持存储大于250M的数据,并且是异步执行的。)

WebSQL【官方不再维护,仅作了解】

  • WebSQL数据库API并不是HTML5规范的一部分。但是它是一个独立的规范,引入了一组使用SQL操作客户端数据库的APIS

  • 最新版的safari,chrome和Opera浏览器都支持WebSQL

  • 目前,webSQL已经不再是W3C推荐的规范,官方已经不再维护,因为当前的SQL规范采用SQLite的SQL方言,而作为一个标准,这是不可接收的

  • webSQL使用SQL语言来进行操作,更像是一个关系型数据库,而indexDB则更像是一个非关系型数据库,这也是目前W3c强推的浏览器数据库解决方案。

在WebSQL中,有3个核心方法

  • openDatabase 这个方法使用现有的数据库或者新建的数据库创建一个数据库对象
  • transaction 这个方法让我们能够控制一个事务,以及基于这种情况执行提交或者回滚(事务失败就会发生回滚)
  • executeSql 这个方法用于执行实际的SQL查询
打开数据库

用openDatebase()方法来打开已经存在的数据库,如果数据库不存在,则会创建一个新得数据库,使用代码如下:

openDatabase()方法对应5个参数

  • 数据库名称
  • 版本号
  • 描述文本
  • 数据库大小
  • 创建回调
<body> <script> var db=openDatabase('mydb','1.0','Test DB',2*1024*1024)</script> </body>

上面的代码表示,打开一个名为mydb的数据库,如果不存在,则会创建该数据库,版本号为1.0,大小为2M.

执行操作

使用代码database.transaction()创建表格和数据

database.transaction(function(tx){tx.executeSql()})

executeSql(sqlStatement,arguments,callback,errorCallback)
该方法有4个参数

  • SQL语句
  • 参数
  • 执行SQL语句后的回调
  • 错误回调

静态插入数据:

<body> <script>// 返回数据库的实例var db=openDatabase('mydb','1.0','Test DB',2*1024*1024)// 实例上调用方法,接收一个回调函数db.transaction(function(tx){//tx 是一个SQLTransaction对象,后面的所有操作都基于该对象。//创建表格tx.executeSql('CREATE TABLE IF NOT EXISTS STU(stuId unique,stuName)')//插入字段tx.executeSql('INSERT INTO STU(stuId,stuName) values(1,"胡文浩")')tx.executeSql('INSERT INTO STU(stuId,stuName) values(2,"张三")')})</script> </body>

动态插入数据:

 <body><script>var stuName="李四"// 返回数据库的实例var db=openDatabase('mydb','1.0','Test DB',2*1024*1024)// 实例上调用方法,接收一个回调函数db.transaction(function(tx){//tx 是一个SQLTransaction对象,后面的所有操作都基于该对象。//创建表格tx.executeSql('CREATE TABLE IF NOT EXISTS STU(stuId unique,stuName)')//插入字段// tx.executeSql('INSERT INTO STU(stuId,stuName) values(1,"胡文浩")')// tx.executeSql('INSERT INTO STU(stuId,stuName) values(2,"张三")')//动态插入tx.executeSql('INSERT INTO STU(stuId,stuName) values(3," />,[stuName])})</script> </body>

在上面的代码中,我们使用动态值得方式插入了一条数据,实例中的stuName是外部变量,excuteSql会映射数组参数中的每条目给”?”

注意:由于上一次操作已经插入了id为1和2的数据,所以这一次插入内容时,要把前两次的插入语句注释,否则插入操作不会成功。因为这里是一个事务,前面失败了会导致后面也失败,事务失败会发生回滚

读取数据
// 读取数据db.transaction(function(tx){tx.executeSql('SELECT * FROM STU',[],function(tx,result){console.log(result.rows) //拿到数据msg=`

查询到的数据条数一共有:${result.rows.length}

`
content.innerHTML+=msgfor(var i =0;i<result.rows.length;i++){msg=`

${result.rows.item(i).stuName}

`
content.innerHTML+=msg}},null)})

删除数据
// 删除数据var stuId=1db.transaction(function(tx){ tx.executeSql('DELETE FROM STU WHERE stuId=" />,[stuId])})

修改数据

要修改数据也是使用SQL中的语法,同样也支持动态指定的方式

var stuName="寒冰"db.transaction(function(tx){tx.executeSql('UPDATE STU SET stuName=" />,[stuName])})

indexedDB

indexedDB 简介

随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量的数据存储在客户端,这样可以减少服务端获取数据,直接从本地获取数据。

现有的浏览器数据存储方案

  • cookie 大小不超过4kb
  • LocalStorage 大小在2.5M到10M之间(各家浏览器不同),而且只存储键值对,不提供搜索功能,不能建立自定义的索引。

MDN官网是这样解释indexedDB的

indexedDB是一种底层API,用于客户端存储大量的结构化数据,webStorage存储少量数据很有用,但是对于存储大量的结构化数据来说力不从心,而indexedDB很好的提供乐这种场景的解决方案。

通俗的说,indexedDB就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。indexedDB允许存储大量的数据,提供查找的接口,还能建立索引,这些都是localstorage不具备的,就数据库类型而言,indexDB不属于关系型数据库(不支持SQL查询语句),更接近于NoSQL数据库。

indexedDB具有以下特点

  • 键值对存储
  • 异步
  • 支持事务(失败就会回滚)
  • 同源限制,每一个数据库对应创建它的域名
  • 存储空间大
  • 支持二进制存储

indexedDB只要用于哪些场景

  • 数据可视化等界面,大量数据,每次请求会消耗很大的性能
  • 即时聊天工具,大量信息需要存在本地
  • 其他存储方式容量不满足时

indexedDB重要概念

indexedDB是一个比较复杂的API,它把不同的实体,抽象成一个个对象接口。学习这个API,就是学习它的各种对象接口。

  • 数据库:IDBDatabase对象
    一系列相关数据的容器,每个域名都可以新建任意多个数据库。
    indexedDB数据库有版本的概念,同一个时刻,只能有一个版本的数据库存在,如果要修改数据库结构(新增或删除表,索引或者主键),只能通过升级数据库版本完成。

    var request=indexedDB.open(dbName,version) 打开数据库,没有则立马创建request.onsuccess=fucntion(event){db=event.target.result 获取到数据库对象}
  • 对象仓库:IDBObjectStore对象 表
    每个数据库包含若干个对象仓库(object store),它类似于关系型数据库的表格。

    request.onupgradeneeded=function(event){db=event.target.result 数据库对象var objectStore=db.createObjectStore() 创建仓库对象objectStore.createIndex() 创建索引}
  • 索引:IDBIndex对象
    加快查询速度,可以在仓库对象里,为不同的属性添加索引

  • 事务:IDBTransaction对象
    事务就是一连串的操作,要么都成功,失败了都回滚

    var request=db.transaction([storeName) 打开数据对象(表)的一个事务方法 .objectStore(storeName) 打开数据对象() .add(数据库对象,数据对象(),data) 插入数据 /.get(数据库对象,数据对象(),data) 根据key查询 /.getAll(数据库对象,数据对象() 查询全部request.onsuccess=fucntion(){}request.onerror=function(){}
  • 操作请求:IDBRequest对象
    request 操作请求对象 用来监听事件 监听成功或失败或更新

    var request=indexedDB.open(dbName,version) "创建或打开"的数据库对象var deleteRequest=window.indexedDB.deleteDatabase(dbName) "删除"的数据库对象* request.onsuccess* request.onerror* request.onupgradeneeded
  • 指针(游标):IDBCursor对象
    新的概念,比如我们要查询满足某一条件的所有数据时,就需要用到游标,游标一行一行的往下走,游标走到的地方就会返回这一行的数据,此时我们便可以对此数据进行判断,是否满足条件。直到数据为空停止。

  • 主键集合:IDBKeyRange对象

IndexDB实操
创建数据库和数据仓库
// js文件中封装一个函数用来创建数据库和数据仓库(表)/** * @param{*} dbName 数据库名称 * @param{*} version 数据库的版本 * **/function openDB(dbName,version=1){return new Promise((resolve,reject)=>{var db; 存储数据库对象// 打开数据库,如果没有就是创建操作var request=indexedDB.open(dbName,version)// 数据库打开或者创建成功request.onsuccess=function(event){ // event.target.result 数据库对象 db=event.target.resultconsole.log('数据库打开成功') resolve(db)}//打开或创建失败request.onerror=function(){ console.log('数据库打开失败');}//数据库发生更新的时候//1.版本号更新 2.添加和删除表的时候//当第一次调用open方法时,会触发这个事件//初始化表request.onupgradeneeded=function(event){console.log('数据库版本更新');db=event.target.result// 创建数据仓库(表)var objectStore= db.createObjectStore("stu",{keyPath:"stuId",//这是主键autoIncrement:true //实现自增})// 创建索引--> 查询更快objectStore.createIndex("stuId","stuId",{unique:true});objectStore.createIndex("stuName","stuName",{unique:false});objectStore.createIndex("stuAge","stuAge",{unique:false});}})}

上述代码封装了一个openDB的函数,该函数调用了indexedDB.open的方法尝试打开一个数据库,如果数据库不存在,就会创建

indexedDB.open方法就会返回一个对象,这个对象上分别监听了成功,失败和更新这三个事件

// 调用封装的函数创建数据库和数据仓库<body><script src="./db.js"></script><script>openDB('stuDB',1.0)</script></body>

关闭数据库
// js文件中封装一个函数用来 关闭数据库/** * 关闭数据库 * @param {object} db数据库实例 ** **/function closeDB(db){db.close();console.log('数据库已关闭')}
删除数据库
// js文件中封装一个函数用来 删除数据库/** * 删除数据库 * @param {object} dbName 数据库名称 **/function deleteDBAll(dbName){console.log(dbName);let deleteRequest=window.indexedDB.deleteDatabase(dbName)deleteRequest.onerror=function(event){console.log('删除失败');}deleteRequest.onsuccess=function(event){console.log('删除成功');}}


插入数据
// js文件中封装一个函数用来 插入数据/** * 插入数据 * @param {*} db 数据库实例 * @param {*} storeName 数据仓库实例(表) * @param {*} data 要添加的数据 * */function addData(db,storeName,data){//创建读写的事务//readwrite 打开模式:读写var request=db.transaction([storeName],'readwrite')//操作数据仓库(表) .objectStore(storeName) .add(data);request.onsuccess=function(){console.log('数据写入成功');},request.onerror=function(){console.log('数据写入失败');}} 
//调用addData<script> //插入数据//因为创建数据库和表的函数返回的是一个成功的promise,所以插入数据要写在后面的then方法中openDB('stuDB','1.0').then((db)=>{addData(db,'stu',{"stuId":1,"stuName":"张三","stuAge":18});addData(db,'stu',{"stuId":2,"stuName":"寒冰","stuAge":25});addData(db,'stu',{"stuId":3,"stuName":"德玛","stuAge":29});addData(db,'stu',{"stuId":4,"stuName":"张2","stuAge":18});addData(db,'stu',{"stuId":5,"stuName":"寒冰2","stuAge":25});addData(db,'stu',{"stuId":6,"stuName":"德玛2","stuAge":29});addData(db,'stu',{"stuId":7,"stuName":"张三","stuAge":18});addData(db,'stu',{"stuId":8,"stuName":"小黄","stuAge":25});addData(db,'stu',{"stuId":9,"stuName":"小王","stuAge":29});addData(db,'stu',{"stuId":10,"stuName":"小李","stuAge":18});addData(db,'stu',{"stuId":11,"stuName":"小吴","stuAge":25});addData(db,'stu',{"stuId":12,"stuName":"大苏打","stuAge":29});addData(db,'stu',{"stuId":13,"stuName":"牛人","stuAge":18});addData(db,'stu',{"stuId":14,"stuName":"大哥","stuAge":25});addData(db,'stu',{"stuId":15,"stuName":"二哥","stuAge":29});addData(db,'stu',{"stuId":16,"stuName":"三哥","stuAge":18});addData(db,'stu',{"stuId":17,"stuName":"四哥","stuAge":25});addData(db,'stu',{"stuId":18,"stuName":"张大头","stuAge":29});addData(db,'stu',{"stuId":19,"stuName":"李寿子","stuAge":18});addData(db,'stu',{"stuId":20,"stuName":"武器求","stuAge":25});addData(db,'stu',{"stuId":21,"stuName":"唐太宗","stuAge":29}); } ) </script>

读取数据

根据需求不同有不同的方式读取

1. 根据key查询

// js中封装一个根据key查询的方法/** * 通过主键来读取数据 * @param {any} db 数据库实例对象 * @param {any} storeName 数据仓库(表) 实例对象 * @param {any} key 主键 * */function getDataByKey(db,storeName,key){return new Promise((resolve,reject)=>{ var request= db.transaction([storeName]).objectStore(storeName).get(key)request.onsuccess=function(){resolve(request.result)};request.onerror=function(){console.log('数据查询失败');}})}
// 调用根据key查询的方法openDB('stuDB','1.0').then((db)=>{//根据key查询 returngetDataByKey(db,'stu',2) }).then(stuInfo=>{console.log(stuInfo);})


2. 查询全部数据

// js中封装一个函数,用来查询所有的数据/** * 查询所有数据 * @param {any} db 数据库实例对象 * @param {any} storeName 数据仓库(表) 实例对象* */function getAllData(db,storeName){return new Promise((resolve,reject)=>{ var request= db.transaction([storeName]).objectStore(storeName).getAll()request.onsuccess=function(){resolve(request.result)};request.onerror=function(){console.log('数据查询失败');}})}
//调用查询全部数据的方法openDB('stuDB','1.0').then((db)=>{//根据key查询 returngetAllData(db,'stu',2) }).then(stuInfo=>{console.log(stuInfo);})

3.通过指针进行查询

// js中封装一个函数,用来通过指针查询/** * 通过游标(指针)来查询所有的数据 * @param {*} db * @param {*} storeName*/function cursorGetData(db,storeName){ return new Promise((resolve,reject)=>{ var list=[] //用于存放所有的数据 var request= db.transaction([storeName],"readwrite") .objectStore(storeName) .openCursor();//创建一个指针(默认指向第一条数据)request.onsuccess=function(event){ var cursor=event.target.result; // 查看游标有没有返回一条数据 if(cursor){ //指针对象console.log(cursor)list.push(cursor.value)cursor.continue(); //移动到下一条数据 }else{resolve(list) } } })}
// 调用指针查询的函数 openDB('stuDB','1.0').then((db)=>{//根据cursor指针查询return cursorGetData(db,'stu')}).then(stuInfo=>{console.log(stuInfo);})

4.通过索引进行查询

只会返回满足条件的第一条数据

// js中封装一个方法,用来通过索引查询/** * 根据索引来查询数据(只会返回满足条件的第一条数据) * @param {*} db * @param {*} storeName * @param {*} indexName 索引名称 * @param {*} indexValue 索引值 */function getDataIndex(db,storeName,indexName,indexValue){ return new Promise((resolve,reject)=>{//request 为操作请求对象var request=db.transaction([storeName],'readwrite').objectStore(storeName).index(indexName).get(indexValue)request.onsuccess=function(event){ resolve(event.target.result)}request.onerror=function(){console.log('索引查询失败');} })}
// 调用索引查询的函数 openDB('stuDB','1.0').then((db)=>{//根据索引来查询某一条数据//只是通过索引查询的化,只会返回满足条件的第一条数据return getDataIndex(db,'stu','stuAge',18)}).then(stuInfo=>{console.log(stuInfo);})

5.根据索引和游标来查询数据

  • IDBKeysRange对象代表数据库仓库(object store)里面的一组主键,根据这组主键,可以获取仓库或索引里面的一组记录

  • IDBkeyRange.lowerBound() 指定下限

// All keys ≥ xvar r1=IDBkeyRange.lowerBound(x)// All keys > xvar r1=IDBkeyRange.lowerBound(x,true)
  • IDBKeyRange.upperBound() 指定上限
// All keys ≤ xvar r1=IDBkeyRange.upperBound(x)// All keys < xvar r1=IDBkeyRange.upperBound(x,true)
  • IDBKeyRange.bound() 同事指定上下限
//x ≤ All keys ≤ yvar r1= IDBKeyRange.bound(x,y) //x < All keys < yvar r1= IDBKeyRange.bound(x,y,true,true) //x < All keys≤yvar r1= IDBKeyRange.bound(x,y,true,false) //x ≤All keys< yvar r1= IDBKeyRange.bound(x,y,false,true) 
  • IDBKeyRange.only() 指定只包含一个值
// key=zvar r1 = IDBKeyRange.only(z)
// js中封装一个函数,根据索引和游标来查询数据/** * 根据索引和游标来查询数据 * @param {*} db * @param {*} storeName * @param {*} indexName 索引名称 * @param {*} indexValue 索引值 */function getDataByIndex(db,storeName,indexName,indexValue){return new Promise((resolve,reject)=>{var list=[] //存储所有满足条件的数据 //request 为操作请求对象 var request=db.transaction([storeName],'readwrite') .objectStore(storeName) .index(indexName) .openCursor(IDBKeyRange.only(indexValue))//****request.onsuccess=function(event){ var cursor =event.target.result console.log(cursor); if(cursor){list.push(cursor.value)cursor.continue() }else{ resolve(list) } } request.onerror=function(){ console.log('索引查询失败'); }}) }
// 调用索引和游标查询的函数openDB('stuDB','1.0').then((db)=>{//根据索引和游标查询return getDataByIndex(db,'stu','stuAge',18)}).then(stuInfo=>{console.log(stuInfo);})


6.根据分页查询数据

indexedDB 分页查询不像MySql分页查询那么简单,没有提供现成的API,如limit等,所以需要我们自己实现分页

// js中封装一个函数,根据分页查询数据/** * 根据索引和游标分页查询记录 * @param {Object} db数据库实例 * @param {string } storeName 仓库名称 * @param {string} indexName 索引名称 * @param {string} indexValue 索引值 * @param {number} page 页码 * @param {number} pageSize 查询条数*/function cursorGetDataByIndexAndPage(db,storeName,indexName,indexValue,page,pageSize){ return new Promise((resolve,reject)=>{var list=[] //用于存储当前页的分页数据var counter=0 //创建一个计数器var isPass=true; //是否要跳过数据varrequest=db.transaction([storeName],'readwrite') .objectStore(storeName) .openCursor();//创建一个游标对象(目前指向第一条数据)request.onsuccess=function(event){ var cursor=event.target.result// 判断是否要跳过一些数据 if(page>1 && isPass){isPass=falsecursor.advance((page-1)*pageSize) //跳过数据return; } if(cursor){list.push(cursor.value)counter++if(counter<pageSize){ cursor.continue()}else{ curser=null; resolve(list)} }else{ resolve(list) }} })}
// 调用分页查询的函数openDB('stuDB','1.0').then((db)=>{ return cursorGetDataByIndexAndPage(db,'stu','','',4,5)}).then(stuInfo=>{console.log(stuInfo);})

7.更新

用put方法执行更改,如果没有就新增

默认跟着主键寻找,组件不能变

// 在js中封装一个方法,来更新数据/** * 更新数据,如果没有就新增 * @param {object} db * @param {string} storeName * @param {object} data */function updateDB(db,storeName,data){ return new Promise((resolve,reject)=>{ var request=db.transaction([storeName],'readwrite') .objectStore(storeName) .put(data) request.onsuccess=function(){resolve({status:true,message:'更新数据成功'}) } })}
//调用方法来更新数据openDB('stuDB','1.0').then((db)=>{// 修改数据// 主键不能变return updateDB(db,'stu',{"stuId":13,"stuName":"浩哥无敌","stuAge":28})}).then(stuInfo=>{console.log(stuInfo);})


indexedDB中刷新数据,更新成功

8.删除

两种方式

  • 方式1:通过主键来删 删1条
//在js中封装一个方法 用于删除/** * 删除数据* @param {object} db * @param {string} storeName * @param {number} id */function deleteDB(db,storeName,id){return new Promise((resolve,reject)=>{var request=db.transaction([storeName],'readwrite').objectStore(storeName).delete(id)request.onsuccess=function(){ resolve({ status:true, message:'删除数据成功' })}}) } 
// 调用删除的方法删除主键为4的数据openDB('stuDB','1.0').then((db)=>{ //删除数据 //通过主键来删 return deleteDB(db,'stu',4)}).then(stuInfo=>{console.log(stuInfo);})


  • 方式2 通过索引和游标删除指定的数据 删多条
// 封装一个方法通过索引和游标删除指定的数据 /*** 通过索引和游标删除指定的数据* @param {object} db数据库实例* @param {string} storeName 仓库名称* @param {string} indexName索引名* @param {object} indexValue 索引值* */ function cursorDelete(db,storeName,indexName,indexValue){return new Promise((resolve,reject)=>{var request=db.transaction([storeName],'readwrite').objectStore(storeName).index(indexName) .openCursor(IDBKeyRange.only(indexValue))request.onsuccess=function(event){var cursor=event.target.resultif(cursor){var deleteRequest=cursor.delete()deleteRequest.onsuccess=function(){ resolve({status:true,message:'删除数据成功' })}}}}) }
// 调用通过索引和游标删除指定的数据的方法// 调用删除的方法删除主键为4的数据openDB('stuDB','1.0').then((db)=>{//通过游标和索引删除 删除多条return cursorDelete(db,'stu','stuAge',28)}).then(stuInfo=>{console.log(stuInfo);})

另外,由于indexedDB所提供的原生api比较复杂,所以现在出现了基于indexedDB封装的库,例如Dexie.js indexedDB的封装库Dexie

File System

File API 概述

以前,用户直接上传图片到服务器存储,然后服务器再将图片的地址返还回来,这样图片就能预览在页面上。这样做,会导致服务器有大量冗余的图片。而文件的大小,类型,验证都放在后端。

html有专门的上传文件的表单控件,这样用户体验会非常的差,客户端没法对用户选择的图片进行validate,无法获取文件的大小,无法预览和选择文件类型。如果是多文件传输,,javascript更是回天乏力。

现在,html提供了file API来帮助不通过服务器实现文件预览和图片预览,该接口允许JavaScript读取本地文件,但并不能直接访问本地文件,而是要依赖于用户行为,比如,用户在 type=”file”控件上选择了某个文件或者用户将文件拖拽到浏览器上。

File Api 提供了以下几个接口来访问本地文件系统

  • File 单个文件,提供了诸如name,file size,minetype等只读文件属性
  • FileList 一个类数组File对象集合
  • FileReader:异步读取文件的接口
  • Blob 文件对象的二进制原始数据

File对象

File对象代表一个文件,用来读写文件信息。它继承了Blob对象,或者说是一种特殊的Blob对象,所有可以使用Blob对象的场合都可以使用它。

最常见的使用场合是表单的文件,用户选中文件之后,浏览器会生成一个数组,里面是每一个用户选中的文件,他们都是file实例对象。

<body><input type="file" name="" id="file" multiple><script>var file=document.getElementById('file') //拿到控件file.onchange=function(event){ //绑定change事件 console.log(event.target.files)//fileList,包含多个file对象}</script></body>

构造函数

浏览器原生提供了一个File()构造函数,用来构建File实例对象

new File(array,name,[{options}])

File()构造函数接收三个参数

  • Array 一个数组,成员可以是二进制或字符串,表示文件的内容
  • name 字符串,表明文件名或文件路径
  • options 配置对象,设置实例的属性,【可选】
    • 属性:type 字符串,表示实例对象的MIME类型,默认值为空字符串
    • 属性:lastModified 时间戳,表示上次修改的时间,默认为Date.now()
var file=new File(['foo'],'foo.txt',{ type: 'text/plain'})console.log('创建时间',file.lastModified)console.log('创建文件文字',file.name)console.log('创建文件的大小',file.size)console.log('创建的文件类型',file.type)

FileList对象

  • FileList是一个类数组,每一个成员都是一个file实例
  • 文件控件通过change事件的event.target.files返回的就是一个FileList实例
  • 获取FileList类数组中第几个文件的方式
var file=document.getElementById('file')file.onchange=function(event){ var myFileList=event.target.files // 方式1:myFileList.item(0)// 方式2:myFileList[o]}

FileReader对象

  • 用来读取File对象或Blob对象所包含的文件内容
  • 浏览器提供了FileReader构造函数,用来生成FileReader实例
var readerFile=new FileReader()

FileReader有以下的实例属性

  • FileReader.onload load事件,读取操作完成的监听函数,通常在这个函数里面使用result属性,拿到文件内容。 ++event.target.result++

  • FileReader.error 读取文件时产生的错误对象

  • FileReader.readyState 表示读取文件时当前的状态,0 尚未加载,1数据正在加载,2表示加载完成

  • FileReader.result 读取完成后的文件内容,有可能是字符串,有可能是一个ArrayBuffer实例。

  • FileReader.onabort abort事件,用户终止读取操作的监听函数

  • FileReader.onloadstart loadstart事件,读取操作开始的监听函数

  • FileReader.onloadend loadend事件,读取操作结束的监听函数

  • FileReader.onprogress progress事件,读取操作进行中的监听函数

FileReader有以下的实例方法

  • FileReader.readAsText() 读取文件的内容,读取完成后,result属性将返回文件内容的文本字符串,参数1是代表文件的Blob实例,第二个参数可选项,表示文本编码,默认为UTF-8.

  • FileReader.readAsDataURL() 读取图片,读取完成后,result属性返回一个Data URL格式(Base64编码)的字符串,代表图片内容。可直接用于img元素的src标签,如果需要base64解码,必须要把前缀data:***;base63从字符串中删除以后,再进行解码。

  • FileReader.abort() 终止读取操作,readyState属性将变成2

  • FileReader.readAsArrayBuffer() 以ArrayBuffer的格式读取文件,读取完成后result属性将返回一个ArrayBuffer实例

  • FileReader.readAsBinaryString() 读取完后,result属性将返回原始的二进制数据

// 小案例:读取文本文件和读取图片<body><input type="file" name="" id="file"><img src="" alt="" width="200"><script>var file=document.getElementById('file')file.onchange=function(event){var fileHandle=event.target.files[0]console.log(fileHandle);// 异步读取文本文件 readAsText// var reader=new FileReader()// reader.readAsText(fileHandle)// reader.οnlοad=function(event){// console.log(event.target.result)// }//异步读取图片直接在页面预览 readAsDateUrlvar reader=new FileReader()reader.readAsDataURL(fileHandle)reader.onload=function(event){ let img=document.querySelector('img') img.src=event.target.result}}</script></body>

File System Access API(了解)

  • File System Access API和File API是两套规范,

  • File System Access API提供了比较稳妥的本地文件交互模式,即保证了实用价值,又保障了用户的数据安全。从打开、到编辑、到保存、一套到底

  • 但是,目前,只有chrome谷歌支持该API.