移动端本地文件处理-SQlite

1,798 阅读4分钟

之前有遇到一个需求:在不使用后端服务的情况下,支持在移动端动态查看某公司OA部门员工状态数据。

整个前端H5项目基于uni-app开发,使用的框架是Vue

实现思路

  • 是否可以把数据通过某种形式保存到手机本地缓存中
  • 是否能够在打开某app或者小程序能直接获取到手机本地缓存的数据来渲染页面
  • 全程后端不参与,那么前端能否访问手机内部文件,并且自动解析文件内容并生成json数据
  • 拿到json数据后,可以通过什么样的方式存到手机本地存储中,并且可以支持条件查询筛选功能

SQLite

SQLite模块用于操作本地数据库文件,可实现数据库文件的创建,执行SQL语句等功能。

具体API参考官方文档

image.png

// 判断数据库是否打开
plus.sqlite.isOpenDatabase({
    name: dbName,
    path: dbPath
})
// 打开数据库
plus.sqlite.openDatabase({
    name: dbName,
    path: dbPath,
    success:fn
    fail:fn
})
// 关闭数据库
plus.sqlite.closeDatabase({
    name: dbName,
    path: dbPath,
    success:fn
    fail:fn
})
// 表格的相关操作 
// 根据sql的不同可以实现表格的创建、删除、插入等
plus.sqlite.selectSql({
    name: dbName,
    sql: sql,
    success:fn
    fail:fn
})

uni-app使用SQLite

1.选中SQLite image.png

2.自定义调试基座 参考链接uniapp 安卓手机真机模拟

3.根据SQlite文档实现相关操作

  打开数据库、关闭数据库、创建表、删除表、查询数据、新增数据、删除数据等

需求实现

uniapp端实现选择手机内部文档,通过前端解析文档内容生成json数据 获取json后,使用sqlite对本地缓存下数据进行处理 查询相关数据进行页面渲染

选择并获取文件

1)H5端

普通的PC端web或者H5,有dom操作对象,可以通过传统的input标签的点击和change事件实现

2)App端

非H5的uni-app是没有dom对象的,一般会直接在插件商城中下载安装常用的文件选择获取插件,来获取文件的path image.png

根据获取的文件路径或者文件对象获取文件内容

1)H5端

HTML

<input type="file" id="myfile" name="myfile" style="display:none" />
<button id="uploader" style="width: 200px; height: 50px;" onclick="document.getElementById('myfile').click()">上传</button>

JS


// 监听input的change事件,最终获取当前选择的文件对象
document.getElementById('myfile').onchange = (event) => {
    var selectedFile = event.target.files[0];
    console.log(selectedFile)
    // 新建FileReader对象
    var reader = new FileReader();
    reader.onload = function(event) {
        // 获取当前文件内容
        var data = event.target.result;
    }
    // 读取上传文件为二进制
    reader.readAsBinaryString(selectedFile);
}

2)App端

首页通过导入的插件选择获取到当前文件的路径, 根据plus.io获取具体文件对象 plus.io.FileReader, fileReader.readAsDataURL , fileReader.readAsText

fileReader:function(){
  const self = this;
  // 请求本地系统文件对象 plus.io.PRIVATE_WWW:应用运行资源目录常量
  plus.io.requestFileSystem( plus.io.PRIVATE_DOC, function(fobject){
  // fs.root是根目录操作对象DirectoryEntry
  fobject.root.getFile('config.xml',{create:true},function(fileEntry){
      fileEntry.file( function(file){
          var fileReader = new plus.io.FileReader();
          fileReader.readAsText(file, 'utf-8');
          fileReader.onloadend = function(evt) {
              //evt 里面包含有当前文件的具体内容,但是不同文件类型的编码格式不确定,目前api中只有txt和img
          }
      });
   });
});
},

解析文件内容,生成JSON字符串

plus.io

上述有说到,在app端,通过plus.io获取文件内容,目前只支持两种编码格式 fileReader.readAsDataURL 以URL编码格式读取文件数据内容,适用于图片类型 fileReader.readAsText 以文本格式读取文件数据内容,适用于txt文本类型

excel类型的文件应该怎么做?

之前考虑说是否可以根据上面的两个api来获取并手动转码的形式来获取具体的内容生成json,但是在编码格式上一直是有问题的,所以目前来说,对于excel文件还没有找到app端的实现方式(遗留问题 有知道的小伙伴🐒我)

那么我们是不是可以通过在app端嵌入H5的方式实现?

web-view

采用web-view标签,嵌入H5页面

<web-view src="/hybrid/html/index.html" @message="handleMessage"></web-view>

注意:

1. h5页面必须在项目目录:hybrid/html/下面,因为这样uni-app才不会进行编译

image.png

2. uniapp跳转webview后H5会执行UniAppJSBridgeReady回调

// 跳转后
document.addEventListener('UniAppJSBridgeReady', function() {
   // 具体实现文件选择、获取、内容格式转换、向uni-app传值代码都卸载这个回调里
})

3. H5页面向uni-app传值

uni.postMessage({
    data: XL_row_object
});

4. @message事件是h5页面向应用发送数据的回调

// uniapp获取webview传来的值
 handleMessage(evt) {
    this.dataInfo = evt.detail.data
 }

XLSX

excel格式化

var workbook = XLSX.read(data, {
    type: 'binary'
});
console.log(event.target.result)
workbook.SheetNames.forEach(function(sheetName) {
var XL_row_object = XLSX.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);
if (XL_row_object.length > 0) {					          console.log(JSON.stringify(XL_row_object));
        //向uniapp传值
        uni.postMessage({
            data: XL_row_object
        });
    }
})

通过SQlite语法操作JSON

前端将获取到的JSON内容通过SQlite存入到本地存储中,关闭数据库连接后,本地存储的内容依然存在

访问数据库连接,查询对应的数据信息并渲染到APP页面上

完整代码

H5

<!DOCTYPE html>
<html lang="zh-cn">
    <head>
        <meta charset="utf-8">
        <title>附件上传</title>
    </head>
    <body>
        <h1>附件上传</h1>
        <input type="file" id="myfile" name="myfile" style="display:none" />
        <button id="uploader" style="width: 200px; height: 50px;" onclick="document.getElementById('myfile').click()">上传</button>
        <!-- uni 的 SDK -->
        <script type="text/javascript" src="js/uni.webview.1.5.2.js"></script>
        <script type="text/javascript" src="js/xlsx.mini.js"></script>
        <script type="text/javascript">
            // 跳转后
            document.addEventListener('UniAppJSBridgeReady', function() {
                    document.getElementById('myfile').onchange = (event) => {
                        var selectedFile = event.target.files[0];
                        console.log(selectedFile)
                        var reader = new FileReader();
                        reader.onload = function(event) {
                        var data = event.target.result;
                        console.log(typeof event.target.result)
                        var workbook = XLSX.read(data, {
                            type: 'binary'
                        });
                        workbook.SheetNames.forEach(function(sheetName) {
                            var XL_row_object = XLSX.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);
                            if (XL_row_object.length > 0) {
                                //向uniapp传值
                                uni.postMessage({
                                    data: XL_row_object
                                });
                            }
                        })
                    };
                    reader.onerror = function(event) {
                      console.error("File could not be read! Code " + event.target.error.code);
                    };
                    // 读取上传文件为二进制
                    reader.readAsBinaryString(selectedFile);
                }
            });
        </script>
    </body>
</html>

uni-app

fileUpload.vue

<template>
    <view>
        <template v-if="show">
            <web-view src="/hybrid/html/index.html" @message="handleMessage"></web-view>
        </template>
        <view>
            {{lastInfo}}
        </view>
    </view>
</template>

<script>  
    export default {  
        data() {
            return {
                dataInfo:'',
                show:true,
            }
        },
        computed:{
            lastInfo() {
                return this.dataInfo
            }
        },	
        methods: {  
            handleMessage(evt) {
                this.dataInfo = evt.detail.data
		this.show = false
            }
        },
		
    }  
</script>