首页 > 技术文章 > H5+ 移动app学习之三 App离线存储

hongyedeboke 2016-11-25 17:19 原文

App离线本地存储方案

HTML5+的离线本地存储有如下多种方案:
HTML5标准方案:cookie、localstorage、sessionstorage、websql、indexedDB
HTML5Plus扩展方案:plus.navigator.setCookie、plus.storage、plus.io

    • cookie
      体量最小,可以设置过期时间。不能跨域。
    • localstorage
      适合key、value键值对的存储,数据量一般不超过5M。是常用的轻量数据存储方案。不能跨域
    • sessionstorage
      也是键值对,特点是关闭App就消失了,也不能跨webview,一般不用于持久化数据保存。
    • websql
      是手机端关系型数据库的最佳方案,各种手机都支持。只是该标准不再更新。但是目前手机端重量数据存储的唯一可商用方案。
    • indexedDB
      是HTML5里最新的数据存储规范,但不是基于SQL,而是基于对象。
      indexedDB性能更高,全是异步处理,学习难度偏大。最重要的是目前手机端支持度不行。Android4.4以上和iOS8以上才支持indexedDB。
    • plus.navigator.setCookie
      与HTML5的标准cookie相比,plus的扩展主要是为了跨域。所谓跨越,就是本地HTML页面和服务器HTML页面共享cookie数据,或者说本地页面的js可以操作服务器页面产生的cookie。如果没有跨越需求,不需要使用plus扩展。
    • plus.storage
      plus.storage也是键值对数据存储。它是把OS给原生App使用的键值对存储数据库封装一层给JS使用。
      plus.storage没有理论上的大小限制。
      plus.storage相比于localstorage 还有一个特点是可跨域。当一个存储数据,需要被本地和来自服务器的页面同时读写时,就涉及跨域问题。此时HTML5的localstorage不能满足需求,只能使用plus.storage。
      plus.storage操作要比localstorage慢几十毫秒,如果不是因为大小限制或跨越,尽量使用localstorage。
      有网友封装了一个框架,针对key-value数据,在localstorage超过5m时自动切换到plus.storage,参考http://ask.dcloud.net.cn/article/552。虽然这么做听起来有点复杂,但我们对这种追求性能极致的开发者非常赞赏。
    • plus.io
      plus.io是文件读写,虽然也可以通过读写txt等文件存储数据,但并不如专业的storage和websql方便。
      plus.io更多的是用于图片等多媒体文件的本地保存。
      比如图文列表的离线使用,一般有2种做法:

       1.图片下载不通过img的src,而是plus.dowload下载的,先下载图片,存好路径后,然后img的src动态指定文件路径

       2.图片使用img的src下载,然后用canvas把img存成图片文件。下次不联网,img的scr直接指向本地文件

 

有人问原生的sqllite是否可用,5+里没有封装,推荐使用HTML5标准的数据库。
还有人问为啥不封装sqllite?因为HTML5已经有了,HTML5+规范无法重复立项。
HTML5+从属于w3c指导下的联盟,DCloud也是w3c会员,重复发明轮子没有好处,只会增加工作量和增大包体积。

有人问三方清理工具清理垃圾会不会造成某些数据丢失,这个可能性是存在的,但概率并不高,取决于清理软件会不会分析你的存储数据里哪些是可以清除的垃圾数据。除了OS的清理工具外,一般没有root权限的清理工具是拿不到除了plus.io外的你的app的存储数据的。

 

cookie

Cookies 是一些数据, 存储于你电脑上的文本文件中。Cookie是用于维持服务端会话状态的,通常由服务端写入,在后续请求中,供服务端读取。

 websql

 HBuild Hybrid App开发 Websql增删改查操作

封装好的websql.js

/**
*数据库操作辅助类,定义对象、数据操作方法都在这里定义
*/
var dbname='websql';/*数据库名*/
var version = '1.0'; /*数据库版本*/
var dbdesc = 'websql练习'; /*数据库描述*/
var dbsize = 2*1024*1024; /*数据库大小*/
var dataBase = null; /*暂存数据库对象*/
/*数据库中的表单名*/
var websqlTable = "websqlTable";

/**
 * 打开数据库
 * @returns  dataBase:打开成功   null:打开失败
 */
function websqlOpenDB(){
    /*数据库有就打开 没有就创建*/
    dataBase = window.openDatabase(dbname, version, dbdesc, dbsize,function() {});
    if (dataBase) {
        alert("数据库创建/打开成功!");
    } else{
        alert("数据库创建/打开失败!");
    }
    return dataBase;
}
/**
 * 新建数据库里面的表单
 * @param tableName:表单名
 */
function websqlCreatTable(tableName){
//  chinaAreaOpenDB();
    var creatTableSQL = 'CREATE TABLE IF  NOT EXISTS '+ tableName + ' (rowid INTEGER PRIMARY KEY AUTOINCREMENT, NAME text,AGE text,HEIGHT text,WEIGTH text)';
    dataBase.transaction(function (ctx,result) {
        ctx.executeSql(creatTableSQL,[],function(ctx,result){
            alert("表创建成功 " + tableName);
        },function(tx, error){ 
            alert('创建表失败:' + tableName + error.message);
        });
    });
}
/**
 * 往表单里面插入数据
 * @param tableName:表单名
 * @param NAME:姓名
 * @param AGE:年龄
 * @param HEIGHT:身高
 * @param WEIGTH:体重
 */
function websqlInsterDataToTable(tableName,NAME,AGE,HEIGHT,WEIGTH){
    var insterTableSQL = 'INSERT INTO ' + tableName + ' (NAME,AGE,HEIGHT,WEIGTH) VALUES (?,?,?,?)';
    dataBase.transaction(function (ctx) {
        ctx.executeSql(insterTableSQL,[NAME,AGE,HEIGHT,WEIGTH],function (ctx,result){
            console.log("插入" + tableName  + NAME + "成功");
        },
        function (tx, error) {
            alert('插入失败: ' + error.message);
        });
    });
}
/**
 * 获取数据库一个表单里面的所有数据
 * @param tableName:表单名
 * 返回数据集合
 */
function websqlGetAllData(tableName){   
    var selectALLSQL = 'SELECT * FROM ' + tableName;
    dataBase.transaction(function (ctx) {
        ctx.executeSql(selectALLSQL,[],function (ctx,result){
            alert('查询成功: ' + tableName + result.rows.length);
            var len = result.rows.length;
            for(var i = 0;i < len;i++) {
                console.log("NAME = "  + result.rows.item(i).NAME);
                console.log("AGE = "  + result.rows.item(i).AGE);
                console.log("HEIGHT = "  + result.rows.item(i).HEIGHT);
                console.log("WEIGTH = "  + result.rows.item(i).WEIGTH);
                console.log("-------- 我是分割线 -------");
            }
        },
        function (tx, error) {
            alert('查询失败: ' + error.message);
        });
    });
}
/**
 * 获取数据库一个表单里面的部分数据
 * @param tableName:表单名
 * @param name:姓名
 */
function websqlGetAData(tableName,name){    
    var selectSQL = 'SELECT * FROM ' + tableName + ' WHERE NAME = ?'
    dataBase.transaction(function (ctx) {
        ctx.executeSql(selectSQL,[name],function (ctx,result){
            alert('查询成功: ' + tableName + result.rows.length);
            var len = result.rows.length;
            for(var i = 0;i < len;i++) {
                console.log("NAME = "  + result.rows.item(i).NAME);
                console.log("AGE = "  + result.rows.item(i).AGE);
                console.log("HEIGHT = "  + result.rows.item(i).HEIGHT);
                console.log("WEIGTH = "  + result.rows.item(i).WEIGTH);
            }
        },
        function (tx, error) {
            alert('查询失败: ' + error.message);
        });
    });
}
/**
 * 删除表单里的全部数据
 * @param tableName:表单名
 */
function websqlDeleteAllDataFromTable(tableName){
    var deleteTableSQL = 'DELETE FROM ' + tableName;
    localStorage.removeItem(tableName);
    dataBase.transaction(function (ctx,result) {
        ctx.executeSql(deleteTableSQL,[],function(ctx,result){
            alert("删除表成功 " + tableName);
        },function(tx, error){ 
            alert('删除表失败:' + tableName + error.message);
        });
    });
}
/**
 * 根据name删除数据
 * @param tableName:表单名
 * @param name:数据的姓名
 */
function websqlDeleteADataFromTable(tableName,name){
    var deleteDataSQL = 'DELETE FROM ' + tableName + ' WHERE NAME = ?';
    localStorage.removeItem(tableName);
    dataBase.transaction(function (ctx,result) {
        ctx.executeSql(deleteDataSQL,[name],function(ctx,result){
            alert("删除成功 " + tableName + name);
        },function(tx, error){ 
            alert('删除失败:' + tableName  + name + error.message);
        });
    });
}
/**
 * 根据name修改数据
 * @param tableName:表单名
 * @param name:姓名
 * @param age:年龄
 */
function websqlUpdateAData(tableName,name,age){
    var updateDataSQL = 'UPDATE ' + tableName + ' SET AGE = ? WHERE NAME = ?';
    dataBase.transaction(function (ctx,result) {
        ctx.executeSql(updateDataSQL,[age,name],function(ctx,result){
            alert("更新成功 " + tableName + name);
        },function(tx, error){ 
            alert('更新失败:' + tableName  + name + error.message);
        });
    });
}


html文件

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black">
        <title></title>
        <script type="text/javascript" src="../../js/websql.js" ></script>
    </head>

    <script>
            function creatTable() {
                console.log("新建数据库");
                websqlOpenDB();
                websqlCreatTable(websqlTable);
            }
            function insterData() {
                console.log("插入数据");
                websqlInsterDataToTable(websqlTable,"小明","18","175cm","60kg");
                websqlInsterDataToTable(websqlTable,"小红","17","160cm","45kg");
                websqlInsterDataToTable(websqlTable,"小强","19","185cm","70kg");
            }
            function updateData() {
                console.log("修改数据");
                websqlUpdateAData(websqlTable,"小明","1000")
            }
            function deleteAData() {
                console.log("删除一条数据");
                websqlDeleteADataFromTable(websqlTable,"小明");
            }
            function deleteAllData() {
                console.log("删除全部数据");
                websqlDeleteAllDataFromTable(websqlTable);
            }
            function selectAData() {
                console.log("查找一条数据");
                websqlGetAData(websqlTable,"小明");
            }
            function selectALlData() {
                console.log("查找全部数据");
                websqlGetAllData(websqlTable);
            }
        </script>

        <style>
            .content {
                padding-top: 50px;
            }
            .websql {
                margin-top: 10px;
            }
            /*设置按钮样式*/
            .websql button{
                height: 44px;
                width: 120px;
            }
        </style>

    <body>
        <div class="content">
            <div class="websql">
                <button type="button" onclick="creatTable()">新建数据库</button>
            </div>
            <div class="websql">
                <!---->
                <button type="button" onclick="insterData()">插入数据</button> 
            </div>
            <div class="websql">
                <!---->
                <button type="button" onclick="deleteAData()">删除一条数据</button>
                <button type="button" onclick="deleteAllData()">删除全部数据</button>
            </div>
            <div class="websql">
                <!---->
                <button type="button" onclick="updateData()">修改数据</button>
            </div>
            <div class="websql">
                <!---->
                <button type="button" onclick="selectAData()">查找一条数据</button>
                <button type="button" onclick="selectALlData()">查找全部数据</button>
            </div>
        </div>
    </body>
</html>

 

 localStorage、sessionStorage

HTML 5 Web 存储

HTML5 提供了两种在客户端存储数据的新方法,本地存储是一个window的属性

  • localStorage - 没有时间限制的数据存储
  • sessionStorage - 针对一个 session 的数据存储

1.区别:

localStorage 方法存储的数据没有时间限制。第二天、第二周或下一年之后,数据依然可用。  

sessionStorage 方法针对一个 session 进行数据存储。当用户关闭浏览器窗口后,数据会被删除。  

2.localStorage API 基本使用方法:

存储数据的方法就是直接给window.localStorage添加一个属性,例如:window.localStorage.a 或者 window.localStorage["a"]。它的读取、写、删除操作方法很简单,是以键值对的方式存在的,如下:

//设值
localStorage.name = "kobi";//设置name为"kobi" localStorage["name"] = "koko";//设置name为"koko",覆盖上面的值 localStorage.setItem("age","18");//设置age为"18"
//取值 var a1 = localStorage["name"];//获取name的值 var a2 = localStorage.age;//获取age的值 var b = localStorage.getItem("name");//获取name的值
//清除 localStorage.removeItem("c");//清除c的值

localStorage.clear();//一次性清除所有的键值对

这里最推荐使用的自然是getItem()和setItem(),清除键值对使用removeItem()。

另外,HTML5还提供了一个key()方法,可以在不知道有哪些键值的时候使用,如下:

//遍历key键值
var
storage = window.localStorage; function showStorage(){   for(var i=0;i<storage.length;i++){     //key(i)获得相应的键,再用getItem()方法获得对应的值     document.write(storage.key(i)+ " : " + storage.getItem(storage.key(i)) + "<br>");    } }

存储大小限制:

IE 9 > 4999995 + 5 = 5000000
firefox 22.0 > 5242875 + 5 = 5242880
chrome  28.0  > 2621435 + 5 = 2621440
safari  5.1   > 2621435 + 5 = 2621440
opera   12.15 > 5M (超出则会弹出允许请求更多空间的对话框)

数据存储异常处理:

try{
     localStorage.setItem(key,value);
}catch(oException){
      if(oException.name == 'QuotaExceededError'){
          console.log('超出本地存储限额!');
          //如果历史信息不重要了,可清空后再设置
          localStorage.clear();
          localStorage.setItem(key,value);
     }
}

 h5+  plus.storage

http://www.cnblogs.com/LoveOrHate/p/4550934.html

//插入N条数据

function setItemFun( id ) {
    //循环插入100调数据
    var dataNum = new Number(id);
    for ( var i=0; i<dataNum; i++ ) {
        plus.storage.setItem( "key"+i, "value"+i );
    }
    var length = getLengthFun();
    outSet( "数据存储成功,存储了"+length+"条数据;" );
}
function getLengthFun(){
    return plus.storage.getLength();
}

//查询所有数据

function getAllItem(){
    outSet( "获取数据:" );
    var itemLength = getLengthFun();
    for ( var i=0; i < itemLength; i++ ) {
        var key = plus.storage.key(i);
          var value = plus.storage.getItem(key);
          outLine( "key:"+key+"-->value:"+value );
    };
}

//删除部分Item

function delItem() {
    outSet( "删除数据:" );
    var itemLength = getLengthFun();
    for (var i=0; i < itemLength; i+=2) {
        var key = plus.storage.key(i);
          plus.storage.removeItem(key);
    };
    var itemNo = getLengthFun();
    outLine( "移除了"+(itemLength-itemNo)+"条数据" );
}

//清除所有内容

function clearAllItem(){
    plus.storage.clear();
    var num = getLengthFun();
    if ( num == 0 ) {
        outSet( "storage数据清除成功!" );
    }else{
        outSet( "storage数据清除失败!" );
    }
}

//修改前五条数据的内容

function modifyTopFive(){
    outSet( "修改前的数据是:" );
    for (var i=0; i < 5; i++) {    
        var key = plus.storage.key(i),value = plus.storage.getItem(key);
          outLine( "key:"+key+"-->value:"+value );
        plus.storage.setItem( key, "新数据值>>"+i );
    };
    outLine( "修改后的数据是:" );
    for (var i=0; i < 5; i++) {
        var key = plus.storage.key(i),value = plus.storage.getItem(key);
        outLine( "key:"+key+"-->value:"+value );
    };
}

 

推荐阅读