• 5-8 uni-app 全端离线本地存储方案


    5-8 uni-app 全端离线本地存储方案

    H5 端

    缓存

    uni.storage
    uni.setStorage({
        key: 'storage_key',
        data: 'hello',
        success: function () {
            console.log('success');
        }
    });
    
    try {
        uni.setStorageSync('storage_key', 'hello');
    } catch (e) {
        // error
    }
    
    uni.getStorage({
        key: 'storage_key',
        success: function (res) {
            console.log(res.data);
        }
    });
    
    try {
        const value = uni.getStorageSync('storage_key');
        console.log(value);
    } catch (e) {
        // error
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    localstorage

    适合 keyvalue 键值对的存储, 数据量一般不超过 5M。是常用的轻量数据存储方案。不能跨域

    保存数据:

    localStorage.setItem("key", "value");
    
    • 1

    读取数据:

    var lastname = localStorage.getItem("key");
    
    • 1

    删除数据:

    localStorage.removeItem("key");
    
    • 1
    sessionstorage

    也是键值对, 特点是关闭 App 就消失了, 也不能跨 webview, 一般不用于持久化数据保存。

    保存数据:

    sessionStorage.setItem("key", "value");
    
    • 1

    读取数据:

    var lastname = sessionStorage.getItem("key");
    
    • 1

    删除数据:

    sessionStorage.removeItem("key");
    
    • 1

    删除所有数据:

    sessionStorage.clear();
    
    • 1
    cookie

    体量最小, 可以设置过期时间。不能跨域。

    保存数据:

    function setCookie(cname, cvalue, exdays) {
        var d = new Date();
        d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
        var expires = "expires=" + d.toGMTString();
        document.cookie = cname + "=" + cvalue + "; " + expires;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    读取数据:

    function getCookie(cname) {
        var name = cname + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i].trim();
            if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
        }
        return "";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    小程序端

    缓存

    uni.storage
    uni.setStorage({
        key: 'storage_key',
        data: 'hello',
        success: function () {
            console.log('success');
        }
    });
    
    try {
        uni.setStorageSync('storage_key', 'hello');
    } catch (e) {
        // error
    }
    
    uni.getStorage({
        key: 'storage_key',
        success: function (res) {
            console.log(res.data);
        }
    });
    
    try {
        const value = uni.getStorageSync('storage_key');
        console.log(value);
    } catch (e) {
        // error
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    静态文件

    App 端

    缓存

    uni.storage
    uni.setStorage({
        key: 'storage_key',
        data: 'hello',
        success: function () {
            console.log('success');
        }
    });
    
    try {
        uni.setStorageSync('storage_key', 'hello');
    } catch (e) {
        // error
    }
    
    uni.getStorage({
        key: 'storage_key',
        success: function (res) {
            console.log(res.data);
        }
    });
    
    try {
        const value = uni.getStorageSync('storage_key');
        console.log(value);
    } catch (e) {
        // error
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    plus.storage
    • 键值对数据存储, 它是把 OS 给原生 App 使用的键值对存储数据库封装一层给 JS 使用
    • 没有理论上的大小限制, 也是持久化的, 不会被当做缓存清理
    • 相比于 localstorage 还有一个特点是可跨域, 当一个存储数据, 需要被本地和来自服务器的页面同时读写时, 就涉及跨域问题, 此时 HTML5localstorage 不能满足需求, 只能使用 plus.storage

    plus.storage 操作要比 localstorage 慢几十毫秒, 尤其是在循环里调用 plus api 会放大这种慢。

    三方清理工具清理垃圾会不会造成某些数据丢失, 但丢失可能性是存在的, 虽然概率并不高, 取决于清理软件会不会分析你的存储数据里哪些是可以清除的垃圾数据。除了 OS 的清理工具外, 一般没有 root
    权限的清理工具是拿不到除了plus.io 外的你的 app 的存储数据的。但 ios 上系统存储空间很少的时候, 系统会清理 cookielocalstoragesessionstoragewebsqlindexedDB 的数据, 此时使用 plus.storageplus.sqllite 更安全。

    // 清除所有存储数据
    function clearStorage() {
        plus.storage.clear();
    }
    
    // 异步清除存储数据
    function clearAsync() {
        plus.storage.clearAsync(function () {
            console.log("clearAsync success");
        }, function (e) {
            console.log("clearAsync failed: " + JSON.stringify(e));
        });
    }
    
    // 获取所有键名
    function getAllKeys() {
        var keys = plus.storage.getAllKeys();
        console.log("keys length: " + keys.length);
    }
    
    // 异步获取所有键名
    function getAllKeysAsync() {
        plus.storage.getAllKeysAsync(function (e) {
                var keys = e.keys;
                console.log("keys length: " + keys.length);
            },
            function (e) {
                console.log("clearAsync failed: " + JSON.stringify(e));
            });
    }
    
    // 获取存储数据的个数
    function storageCount() {
        return plus.storage.getLength();
    }
    
    // 获取存储的键值
    function getStorage() {
        return plus.storage.getItem("test");
    }
    
    // 异步获取存储的键值
    function getStorageAsync() {
        plus.storage.getItemAsync("test", function (e) {
            var data = e.data;
            console.log("getItemAsync success: " + data);
        }, function (e) {
            console.log("getItemAsync failed: " + JSON.stringify(e));
        });
    }
    
    // 获取键值对中指定索引值的key值
    function enumValueByIndex() {
        var keyNames = [];
        var values = [];
        var numKeys = plus.storage.getLength();
        for (var i = 0; i < numKeys; i++) {
            keyNames[i] = plus.storage.key(i);
            values[i] = plus.storage.getItem(keyNames[i]);
        }
    }
    
    // 修改或添加键值(key-value)对数据到应用数据存储中
    function setStorage() {
        plus.storage.setItem("test", "test with hbuilder!");
    }
    
    // 异步存储键值
    function setStorageAsync() {
        plus.storage.setItemAsync("test", "test with HBuilderX", function () {
            console.log("setItemAsync success");
        }, function (e) {
            console.log("setItemAsync failed: " + JSON.stringify(e));
        });
    }
    
    // 删除键值
    function removeStorage() {
        plus.storage.removeItem("test");
    }
    
    // 异步删除键值
    function removeItemAsync() {
        plus.storage.removeItemAsync("test", function () {
            console.log("removeItemAsync success");
        }, function (e) {
            console.log("removeItemAsync failed: " + JSON.stringify(e));
        });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    持久化

    uni.storage

    同 -> App 端 -> 缓存 -> uni.storage

    plus.storage

    同 -> App 端 -> 缓存 -> plus.storage

    plus.sqlite

    plus.sqlite 是对原生的 sqlite 的封装。它也是一种可以通过 sql 在本地增删改查数据库的方案。
    有点类似 websql, 但相对于 websql 而言, sqlite 的好处是:

    • 可以预置基础数据库, 直接打包到 app
    • 当手机空间不足时, websql 可能会被清理, 而 sqlite 不会
    module.exports = {
        dbName: 'chat', // 数据库名称
        dbPath: '_doc/chat.db', // 数据库地址,推荐以下划线为开头   _doc/xxx.db
    
        // 判断数据库是否打开
        isOpen() {
            // 数据库打开了就返回 true,否则返回 false
            var open = plus.sqlite.isOpenDatabase({
                name: this.dbName,  // 数据库名称
                path: this.dbPath  // 数据库地址
            })
            return open;
        },
    
        // 创建数据库 或 有该数据库就打开
        openSqlite() {
            return new Promise((resolve, reject) => {
                // 打开数据库
                plus.sqlite.openDatabase({
                    name: this.dbName,
                    path: this.dbPath,
                    success(e) {
                        resolve(e); // 成功回调
                    },
                    fail(e) {
                        reject(e);  // 失败回调
                    }
                })
            })
        },
    
        // 关闭数据库
        closeSqlite() {
            return new Promise((resolve, reject) => {
                plus.sqlite.closeDatabase({
                    name: this.dbName,
                    success(e) {
                        resolve(e);
                    },
                    fail(e) {
                        reject(e);
                    }
                })
            })
        },
    
        // 数据库建表 sql:'CREATE TABLE IF NOT EXISTS dbTable("id" varchar(50),"name" TEXT) 
        // 创建 CREATE TABLE IF NOT EXISTS 、 dbTable 是表名,不能用数字开头、括号里是表格的表头
        createTable(dbTable, data) {
            return new Promise((resolve, reject) => {
                // executeSql: 执行增删改等操作的SQL语句
                plus.sqlite.executeSql({
                    name: this.dbName,
                    sql: `CREATE TABLE IF NOT EXISTS ${dbTable}(${data})`,
                    success(e) {
                        resolve(e);
                    },
                    fail(e) {
                        reject(e);
                    }
                })
            })
        },
    
        // 数据库删表 sql:'DROP TABLE dbTable'
        dropTable(dbTable) {
            return new Promise((resolve, reject) => {
                plus.sqlite.executeSql({
                    name: this.dbName,
                    sql: `DROP TABLE ${dbTable}`,
                    success(e) {
                        resolve(e);
                    },
                    fail(e) {
                        reject(e);
                    }
                })
            })
        },
    
        // 向表格里添加数据 sql:'INSERT INTO dbTable VALUES('x','x','x')'   对应新增
        // 或者 sql:'INSERT INTO dbTable ('x','x','x') VALUES('x','x','x')'   具体新增
        // 插入 INSERT INTO  、 dbTable 是表名、根据表头列名插入列值
        insertTableData(dbTable, data, condition) {
            // 判断有没有传参
            if (dbTable !== undefined && data !== undefined) {
                // 判断传的参是否有值
                var bol = (JSON.stringify(data) == "{}");
                if (!bol) {
                    if (condition == undefined) {
                        var sql = `INSERT INTO ${dbTable} VALUES('${data}')`;
                    } else {
                        var sql = `INSERT INTO ${dbTable} (${condition}) VALUES(${data})`;
                    }
                    // console.log(sql);
                    return new Promise((resolve, reject) => {
                        // 表格添加数据
                        plus.sqlite.executeSql({
                            name: this.dbName,
                            sql: sql,
                            success(e) {
                                resolve(e);
                            },
                            fail(e) {
                                reject(e);
                            }
                        })
                    })
                } else {
                    return new Promise((resolve, reject) => {
                        reject("错误添加")
                    })
                }
            } else {
                return new Promise((resolve, reject) => {
                    reject("错误添加")
                })
            }
        },
    
        // 根据条件向表格里添加数据  有数据更新、无数据插入
        // (建表时需要设置主键) 例如 --- "roomid" varchar(50) PRIMARY KEY
        insertOrReplaceData(dbTable, data, condition) {
            // 判断有没有传参
            if (dbTable !== undefined && data !== undefined) {
                if (condition == undefined) {
                    var sql = `INSERT OR REPLACE INTO ${dbTable} VALUES('${data}')`;
                } else {
                    var sql = `INSERT OR REPLACE INTO ${dbTable} (${condition}) VALUES(${data})`;
                }
                // console.log(sql);
                return new Promise((resolve, reject) => {
                    // 表格添加数据
                    plus.sqlite.executeSql({
                        name: this.dbName,
                        sql: sql,
                        success(e) {
                            resolve(e);
                        },
                        fail(e) {
                            reject(e);
                        }
                    })
                })
            } else {
                return new Promise((resolve, reject) => {
                    reject("错误添加")
                })
            }
        },
    
        // 查询获取数据库里的数据 sql:'SELECT * FROM dbTable WHERE lname = 'lvalue''
        // 查询 SELECT * FROM 、 dbTable 是表名、 WHERE 查找条件 lname,lvalue 是查询条件的列名和列值
        selectTableData(dbTable, lname, lvalue, cc, dd) {
            if (dbTable !== undefined) {
                // 第一个是表单名称,后两个参数是列表名,用来检索
                if (lname !== undefined && cc !== undefined) {
                    // 两个检索条件
                    var sql = `SELECT * FROM ${dbTable} WHERE ${lname} = '${lvalue}' AND ${cc} = '${dd}'`;
                }
                if (lname !== undefined && cc == undefined) {
                    // 一个检索条件
                    var sql = `SELECT * FROM ${dbTable} WHERE ${lname} = '${lvalue}'`;
                    // console.log(sql);
                }
                if (lname == undefined) {
                    var sql = `SELECT * FROM ${dbTable}`;
                }
                return new Promise((resolve, reject) => {
                    // 表格查询数据  执行查询的SQL语句
                    plus.sqlite.selectSql({
                        name: this.dbName,
                        sql: sql,
                        success(e) {
                            resolve(e);
                        },
                        fail(e) {
                            reject(e);
                        }
                    })
                })
            } else {
                return new Promise((resolve, reject) => {
                    reject("错误查询")
                });
            }
        },
    
        // 删除表里的数据 sql:'DELETE FROM dbTable WHERE lname = 'lvalue''
        // 删除 DELETE FROM 、 dbTable 是表名、 WHERE 查找条件 lname,lvalue 是查询条件的列名和列值
        deleteTableData(dbTable, lname, lvalue, ww, ee) {
            if (dbTable !== undefined) {
                if (lname == undefined) {
                    var sql = `DELETE FROM ${dbTable}`;
                } else {
                    if (ww !== undefined) {
                        // 两个检索条件
                        var sql = `DELETE FROM ${dbTable} WHERE ${lname} = '${lvalue}' AND ${ww} = '${ee}'`;
                    } else {
                        // 一个检索条件
                        var sql = `DELETE FROM ${dbTable} WHERE ${lname} = '${lvalue}'`;
                    }
                }
                return new Promise((resolve, reject) => {
                    // 删除表数据
                    plus.sqlite.executeSql({
                        name: this.dbName,
                        sql: sql,
                        success(e) {
                            resolve(e);
                        },
                        fail(e) {
                            reject(e);
                        }
                    })
                })
            } else {
                return new Promise((resolve, reject) => {
                    reject("错误删除")
                });
            }
        },
    
        // 修改数据表里的数据 sql:"UPDATE dbTable SET 列名 = '列值',列名 = '列值' WHERE lname = 'lvalue'"
        // 修改 UPDATE 、 dbTable 是表名, data: 要修改的列名=修改后列值, lname,lvalue 是查询条件的列名和列值
        updateTableData(dbTable, data, lname, lvalue) {
            if (lname == undefined) {
                var sql = `UPDATE ${dbTable} SET ${data}`;
            } else {
                var sql = `UPDATE ${dbTable} SET ${data} WHERE ${lname} = '${lvalue}'`;
            }
            // WHERE 前面是要修改的列名、列值,后面是条件的列名、列值
            return new Promise((resolve, reject) => {
                // 修改表数据
                plus.sqlite.executeSql({
                    name: this.dbName,
                    sql: sql,
                    success(e) {
                        resolve(e);
                    },
                    fail(e) {
                        reject(e);
                    }
                })
            })
        },
    
        // 获取指定数据条数  sql:"SELECT * FROM dbTable ORDER BY 'id' DESC LIMIT 15 OFFSET 'num'"
        // dbTable 表名, ORDER BY 代表排序默认正序, id 是排序的条件 DESC 代表倒序,从最后一条数据开始拿
        // LIMIT 15 OFFSET '${num}',这句的意思是跳过 num 条拿 15 条数据, num 为跳过多少条数据是动态值
        // 例 初始num设为0,就从最后的数据开始拿15条,下次不拿刚获取的数据,所以可以让num为15,这样就能一步一步的拿完所有的数据
        pullSQL(dbTable, id, num) {
            return new Promise((resolve, reject) => {
                plus.sqlite.selectSql({
                    name: this.dbName,
                    sql: `SELECT * FROM ${dbTable} ORDER BY '${id}' DESC LIMIT 15 OFFSET '${num}'`,
                    success(e) {
                        resolve(e);
                    },
                    fail(e) {
                        reject(e);
                    }
                })
            })
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266

    静态文件

    plus.io

    plus.io 是文件读写, 虽然也可以通过读写 txt 等文件存储数据, 但并不如专业的 storagewebsql 方便。
    plus.io 更多的是用于图片等多媒体文件的本地保存。比如图文列表的离线使用, 一般有 2 种做法:

    • 图片下载不通过 imgsrc, 而是 plus.dowload 下载的, 先下载图片, 存好路径后, 然后 imgsrc 动态指定文件路径
    • 图片使用 imgsrc 下载, 然后用 canvasimg 存成图片文件, 下次不联网, imgscr 直接指向本地文件

    plus.io 文档地址

    其他

    其他的一些下载文件的 API 也可以用作离线存储方案。

  • 相关阅读:
    【尾篇】《信息资源管理》第7章 | 企业与政府信息资源管理
    青少年python系列 45.文件操作1
    制作一个简单HTML传统端午节日网页(HTML+CSS)7页 带报告
    mariadb 错误日志中报错:Incorrect definition of table mysql.column_stats:
    集团公司管控的三种模式:财务管控、运营管控、战略管
    【深入了解回调函数:在编程中的应用和原理】
    Program design PACT analysis
    力扣刷题day45|300最长递增子序列、674最长连续递增序列、718最长重复子数组
    使用MitmProxy离线缓存360度全景网页
    文娱行业搜索最佳实践
  • 原文地址:https://blog.csdn.net/m0_51180924/article/details/126947254