uniapp使用plus.sqlite实现图片视频缓存到手机本地

Posted @逆风boy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uniapp使用plus.sqlite实现图片视频缓存到手机本地相关的知识,希望对你有一定的参考价值。

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

注意:HBuilderX1.7.2及以上版本支持此功能。
方法:

  • openDatabase: 打开数据库
  • isOpenDatabase: 判断数据库是否打开
  • closeDatabase: 关闭数据库
  • transaction: 执行事务
  • executeSql: 执行增删改等操作的SQL语句
  • selectSql: 执行查询的SQL语句

回调方法:

  • SQLiteSuccessCallback: SQLite操作成功回调函数
  • SQLiteFailCallback:SQLite操作失败回调函数

权限:
5+功能模块(permissions)
在hbuilderX项目中的源码图添加下面代码



// ...
"permissions":
	// ...
	"SQLite": 
		"description": "SQLite数据库"
	


或者勾选这个SQLite

实现功能逻辑
sqlite.vue(页面)

<template>
	<view>
		<view class="uni-divider uni-divider__content" style="margin: 50rpx 200rpx; color: red;font-size: 28rpx;">
			测试SQLite如何进行本地存储</view>
		<button @click="openSQL">打开数据库</button>
		<button @click="createTable">创建表</button>
		<button @click="insertTableData">新增表数据</button>
		<button @click="selectTableData">查询表数据</button>
		<button @click="updateTableData">修改表数据</button>
		<button @click="deleteTableData">按条件删除表数据</button>
		<button @click="closeSQL">关闭数据库</button>

		<view class="uni-divider__content" v-for="(item,index) in listData" :key='index'>
			<view>名字:item.name</view>
			<view>内容:item.content</view>
			<view>时间:item.time</view>
			<image :src="item.imgsrc" mode=""></image>
			<video :src="item.videosrc" controls></video>
		</view>
	</view>
</template>

<script>
	// 引入封装的 sqlite
	import DB from "@/utils/sqlite.js";
	import 
		getImageFile,
		getVideoFile
	 from "@/utils/download.js"
	export default 
		data() 
			return 
				listData: [],
				list: []
			;
		,
		onLoad() 
			this.openSQL();
			// this.selectTableData()
		,

		methods: 
			// 打开数据库
			openSQL() 
				// 这个是查询有没有打开数据库
				let open = DB.isOpen();
				console.log("数据库状态", open ? "开启" : "关闭");
				if (!open) 
					DB.openSqlite()
						.then(res => 
							this.showToast("数据库已打开");
						)
						.catch(error => 
							console.log("数据库开启失败");
						);
				
			,

			// 关闭数据库
			closeSQL() 
				// 这个是查询有没有打开数据库
				let open = DB.isOpen();
				if (open) 
					DB.closeSqlite()
						.then(res => 
							this.showToast("数据库已关闭");
						)
						.catch(error => 
							this.showToast("数据库关闭失败");
						);
				
			,

			// 创建表
			createTable() 
				let open = DB.isOpen();
				if (open) 
					this.openSQL();
					let sql =
						'"id" INTEGER PRIMARY KEY AUTOINCREMENT,"name" text,"content" text, "imgsrc" varchar, "videosrc" varchar, "time" text';
					// 创建表 DB.createTable(表名, 表的列)
					DB.createTable("chat", sql)
						.then(res => 
							this.showToast("创建chat表成功");
						)
						.catch(error => 
							this.showToast("创建表失败");
						);
				 else 
					this.showToast("数据库未打开");
				
			,

			// 新增表数据
			insertTableData() 
				let open = DB.isOpen();
				if (open) 
					let arr = [
							name: '测试1',
							content: "离子图片",
							imgsrc: "https://lmg.jj20.com/up/allimg/tp10/211224122S31944-0-lp.jpg",
							videosrc: 'http://vd3.bdstatic.com/mda-ni68ppt2xqskeu9v/360p/h264/1662530911412069950/mda-ni68ppt2xqskeu9v.mp4'
						,
						
							name: '测试2',
							content: "美景图片",
							imgsrc: 'https://lmg.jj20.com/up/allimg/1113/052420110515/200524110515-1-1200.jpg',
							videosrc: 'http://vd3.bdstatic.com/mda-ni68ppt2xqskeu9v/360p/h264/1662530911412069950/mda-ni68ppt2xqskeu9v.mp4'
						,
						
							name: '测试3',
							content: "长白山",
							imgsrc: 'https://lmg.jj20.com/up/allimg/1113/051220112022/200512112022-1-1200.jpg',
							videosrc: 'http://vd3.bdstatic.com/mda-ni68ppt2xqskeu9v/360p/h264/1662530911412069950/mda-ni68ppt2xqskeu9v.mp4'
						
					]
					let fileList = JSON.parse(JSON.stringify(arr))
					const downloadList = []
					fileList.forEach((item, index, arr) => 
						downloadList.push(getImageFile(item.imgsrc, item, index, arr), getVideoFile(item.videosrc,
							item, index, arr))
					)
					Promise.all(downloadList).then(res => 
						fileList.map(item => 
							let time = this.formatDate(new Date().getTime());
							let sql =
								`'$item.name','$item.content','$item.imgsrc','$item.videosrc','$time'`;
							let condition = "'name','content','imgsrc','videosrc','time'";
							// 新增 DB.insertTableData(表名, 对应表头列的数据)
							DB.insertTableData("chat", sql, condition)
								.then(res => 
									this.showToast("新增数据成功");
									this.selectTableData();
								)
								.catch(error => 
									console.log("失败", error);
								);
						)
					)

				 else 
					this.showToast("数据库未打开");
				
			,

			// 查询表数据
			selectTableData() 
				let open = DB.isOpen();
				if (open) 
					// 查询表 DB.selectTableData(表名,查询条件列名,查询条件列值)
					DB.selectTableData("chat")
						.then(res => 
							console.log("contact表数据", res);
							if (res) 
								this.listData = res
							
						)
						.catch(error => 
							console.log("查询失败", error);
						);
				 else 
					this.showToast("数据库未打开");
				
			,

			// 修改表数据
			updateTableData() 
				let open = DB.isOpen();
				if (open) 
					let time = this.formatDate(new Date().getTime());
					let data = `content = '我被修改了',time = '$time'`;
					// 修改表数据 DB.updateTableData(表名, 要修改的列名=修改后列值, 修改条件的列名, 修改条件的列值)
					DB.updateTableData("chat", data, "name", "小明")
						.then(res => 
							this.showToast("更新chat表成功");
							this.selectTableData();
						)
						.catch(error => 
							console.log("修改失败", error);
						);
				 else 
					this.showToast("数据库未打开");
				
			,

			// 删除表数据
			deleteTableData() 
				let open = DB.isOpen();
				if (open) 
					// 删除表 DB.deleteTableData(表名,查询条件列名,查询条件列值)
					DB.deleteTableData("chat", "name", "测试2", )
						.then(res => 
							this.showToast("删除表数据成功");
							this.selectTableData();
						)
						.catch(error => 
							console.log("删除失败", error);
						);
				 else 
					this.showToast("数据库未打开");
				
			,

			// 提示框
			showToast: function(str) 
				uni.showToast(
					icon: "none",
					title: str,
					mask: true
				);
			,

			// 时间戳转年月日
			formatDate(data) 
				let now = new Date(data);
				var year = now.getFullYear(); //取得4位数的年份
				var month =
					now.getMonth() + 1 < 10 ?
					"0" + (now.getMonth() + 1) :
					now.getMonth() + 1;
				var date = now.getDate() < 10 ? "0" + now.getDate() : now.getDate();
				var hour = now.getHours() < 10 ? "0" + now.getHours() : now.getHours();
				var minute =
					now.getMinutes() < 10 ? "0" + now.getMinutes() : now.getMinutes();
				var second =
					now.getSeconds() < 10 ? "0" + now.getSeconds() : now.getSeconds();
				return (
					year +
					"-" +
					month +
					"-" +
					date +
					" " +
					hour +
					":" +
					minute +
					":" +
					second
				);
			
		
	;
</script>

引入自定义sqlite.js文件

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);
        

uniapp文件管理 文件列表 获取媒体文件 图片视频音频文档压缩包文件并实现可删除文件 图片文件列表 视频文件列表 音频文件列表 获取内存卡图片视频音频pdf xlxs docx txt

[前言]
uniapp目前本身并不支持直接获取媒体文件列表,不过因为提供了原生插件使用和开发的功能,问题并不大,接下来进入正题。

Android 10以上的存储机制

因为Android 10以上高版本,开始执行更为安全分区存储机制,对外部存储文件访问方式重新设计,便于用户更好的管理外部存储文件。这个机制遵循三个原则:
1、文件由哪个应用创建,应用不需要存储权限即可以访问应用自己创建文件(这点不错)
2、添加外部存储应用私有目录文件访问限制,现在即使你的应用申请读写权限也不能访问其他应用外部存储私有目录文件(让数据更安全,防止篡改)
3、添加pdf、office、doc等非媒体、图片和音频文件的访问限制,你的应用即使申请了读写权限也无法访问其他应用创建的pdf、office、doc等文件

MediaStore API

MediaStore是Android系统提供的媒体库,可以通过ContentResolver来对媒体库执行查询、修改、删除文件的操作。本文开发的原生插件就是基于此API.

下面是uniapp调用层的方法,在这个方法里用Android代码逻辑编写插件功能。

// 获取文件的中枢函数
@UniJSMethod(uiThread = true)
    public void getFiles(final JSONObject options, UniJSCallback callback,UniJSCallback fail) 
        JSONObject param = new JSONObject();
        param.put("fileType","image");

        if(options != null)
            param = options;
        

        JSONObject data = new JSONObject();
        String fileType = param.getString("fileType");

        ContentResolver resolver = mUniSDKInstance.getContext().getContentResolver();
        switch (fileType)
            case "image": data = FileManageUtils.getAllPhoto(resolver); break;
            case "video": data = FileManageUtils.getAllVideo(resolver); break;
            case "audio": data = FileManageUtils.getAllMusic(resolver); break;
            case "document": data = FileManageUtils.getAllText(resolver); break;
            case "zip": data = FileManageUtils.getAllZip(resolver); break;
        

	 // 到这里已经获取到了文件列表数据, 通过uniapp传过来的回调返回数据
        if(callback != null)
            callback.invoke(data);
        else
            if(fail != null)
                JSONObject result = new JSONObject();
                result.put("code",201);
                result.put("message","获取文件列表失败");
                fail.invoke(result);
            
        
    

获取照片文件列表

对每种类型都进行了一层函数封装,getAllPhoto获取所有图片,getAllVideo获取所有视频,getAllMusic获取或有音频,getAllText获取所有文档,getAllZip获取所有压缩文件。

	// 获取文件列表并进行一个简单封装,返回 list / 长度 / 媒体文件类型
    public static JSONObject getAllPhoto(ContentResolver resolver) 
        String[] projection = new String[]MediaStore.Images.ImageColumns._ID,MediaStore.Images.ImageColumns.SIZE, MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.DISPLAY_NAME;
        List<JSONObject> list = getFiles(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,resolver,null,null,projection,MediaStore.Images.ImageColumns.DISPLAY_NAME,MediaStore.Images.ImageColumns.DATA,MediaStore.Images.ImageColumns.SIZE,MediaStore.Images.ImageColumns._ID);
        JSONObject data = new JSONObject();
        data.put("fileList",list);
        data.put("fileNum",list.size());
        data.put("fileType","image");
        return data;
    

getFile函数的核心代码

这个方法通过外部传入的类型和字段等参数来查询媒体文件,获取一个游标索引,从中可以循环取出数据封装成目标格式。

private static List<JSONObject> getFiles(Uri uri, ContentResolver resolver, String selection, String[] selectionArgs, String[] projection, String colName, String colPath, String colSize, String colId)
        List<JSONObject> files = new ArrayList<>();

        //projection 是定义返回的数据,selection 通常的sql 语句,例如  selection=MediaStore.Images.ImageColumns.MIME_TYPE+"=? " 那么 selectionArgs=new String[]"jpg";
        Cursor cursor = resolver.query(uri, projection, selection, selectionArgs, MediaStore.Images.ImageColumns.DATE_MODIFIED + "  desc");

        float fileSize = 0;
        long fileId = 0;
        String fileName;
        String filePath;

        while (cursor.moveToNext()) 
            fileSize = cursor.getFloat(cursor.getColumnIndex(colSize));
            fileName = cursor.getString(cursor.getColumnIndex(colName));
            filePath = cursor.getString(cursor.getColumnIndex(colPath));
            fileId = cursor.getLong(cursor.getColumnIndex(colId));

            JSONObject obj = new JSONObject();
            obj.put("path",filePath);
            obj.put("size",fileSize);
            obj.put("name",fileName);
            obj.put("id",fileId);
            files.add(obj);
        

        cursor.close();

        return files;
    

uniapp层调用

<template>
	<view>
		<uni-segmented-control 
			:values="['图片','视频','音频','文档','zip']" 
			styleType="button" 
			@clickItem="onClickItem"
			class="segmented-style">
		</uni-segmented-control>
		
		<view class="list-style" v-if="listData && listData.length > 0">
			<view v-for="(item, index) in listData" v-bind:key="index" class="list-item-style" @longpress="longPressEvent(item)">
				<text class="list-item-text">getUnitValue(item.size)</text>
				<image :src="item.path" class="list-item-media-style" v-if="mode === 'image'"></image>
				<view v-else-if="mode === 'video'" style="background-color: bisque;display: flex;align-items: center;justify-content: center;" class="list-item-media-style">
					<image src="../../static/icon_play.png" style="width: 50rpx; height: 50rpx;"></image>
				</view>
				
				<view v-else-if="mode === 'audio'" style="background-color: indianred;display: flex;align-items: center;justify-content: center;" class="list-item-media-style">
					<image src="../../static/icon_audio.png" style="width: 50rpx; height: 50rpx;"></image>
				</view>
			</view>
		</view>
		<view v-else style="color: #999999;min-height: calc(60vh);display: flex;align-items: center;justify-content: center;">
			设备中没有发现该类型文件
		</view>
	</view>
</template>

<script>
	var fileManage = uni.requireNativePlugin("luanqing-file-manage");
	
	export default 
		data() 
			return 
				mode:'image', // 0|图片 1|视频  2|音频  3|文件
				listData:[],
			
		,
		onShow() 
			this.loadFiles();
		,
		methods: 
			longPressEvent(data)
				const $that = this;
				uni.showModal(
					title:'是否确定删除?',
					cancelText:'取消',
					confirmText:'删除',
					complete(res) 
						if(res.confirm)
							console.error("长按删除:",data);
							fileManage.deleteFile(fileType:$that.mode,fileId:data.id, filePath:data.path,(res=>
								console.error("删除成功:",res);
								$that.loadFiles();
							), (res=>
								console.error("删除失败:",res);
							));
						
					
				)
			,
			loadFiles()
				const $that = this;
				console.error("是否是空:",fileManage === undefined || fileManage === null);
				fileManage.getFiles(fileType:this.mode, (res=>
					console.error("接口返回的数据:",res.files);
					$that.listData = res.fileList;
				), (fail=>
					console.error("获取文件列表失败:",fail);
				));
			,
			onClickItem(e)
				this.mode = this.getFileType(e.currentIndex);
				this.loadFiles();
			,
			// 获取文件类型
			getFileType(typeId)
				switch(typeId)
					case 0: return "image";
					case 1: return "video";
					case 2: return "audio";
					case 3: return "document";
					case 4: return "zip";
					default: return "image";
				
			,
			// 计算文件大小值和单位
			getUnitValue(value)
				if(value > 1000000)
					return (value / 1000000).toFixed(1) + 'MB';
				else if(value > 1000)
					return Math.floor(value / 1000).toFixed(1) + 'KB';
				else if(value < 1000)		
					return Math.floor(value / 1000).toFixed(1) + 'KB';
				// return value > 1000 ? 
			
		
	
</script>

<style>
	.segmented-style
		margin-left: 20rpx;
		margin-right: 20rpx;
		margin-top: 25rpx;
	
	.list-style
		display: flex;
		flex-direction: row;
		flex-wrap: wrap;
	
	.list-item-style
		width: 115rpx;
		height: 115rpx;
		margin: 5rpx;
		position: relative;
		background-color: #ffffff;
	
	.list-item-media-style
		width: 115rpx;
		height: 115rpx;
		position: absolute;
		top: 0rpx;
		bottom: 0rpx;
		left: 0rpx;
		right: 0rpx;
		z-index: 10;
	
	.list-item-text
		z-index: 100;
		position: absolute;
		bottom: 0rpx;
		right: 0rpx;
		color: #333333;
		padding: 0rpx 10rpx;
		font-size: 20rpx;
		background-color: #F2F2F2;
	
</style>

链接: 下载地址

示例图:

以上是关于uniapp使用plus.sqlite实现图片视频缓存到手机本地的主要内容,如果未能解决你的问题,请参考以下文章

uniapp文件管理 文件列表 获取媒体文件 图片视频音频文档压缩包文件并实现可删除文件 图片文件列表 视频文件列表 音频文件列表 获取内存卡图片视频音频pdf xlxs docx txt

uniapp分包图片使用方法

Uniapp 图片选择插件(支持视频音频) Ba-MediaPicker

uniapp 图片视频上传

uniapp video 视频暂停,且展示题目

Uniapp 图片选择插件(支持视频音频) Ba-MediaPicker