cocosCreator 之localStorage本地存储和封装拓展

news2024/12/22 21:26:58

版本: 3.8.0

语言: TypeScript

环境: Mac


简介


在cocosCreator中,针对于本地存储主要使用localStorage接口,通过key-value的格式进行存储和读取数据。

主要接口有:

接口描述
setItem(key, value)保存指定索引的数据
getItem(key)获取指定索引的数据
removeItem(key)移除指定索引的数据
clear()清空所有数据

定义文件如下:

// cc.d.ts
export const sys: {
  // HTML5 标准中的 localStorage 的本地存储功能,在 Web 端等价于 window.localStorage
  localStorage: Storage;
}

// lib.dom.d.ts
interface Storage {
    // 返回数据项的数量
    readonly length: number;
    // 移除所有存储的数据
    clear(): void;
    // 根据键名获取数据,如果没有则null
    getItem(key: string): string | null;
    // 获取指定索引处的键名,如果没有则null
    key(index: number): string | null;
    // 根据键名移除指定数据
    removeItem(key: string): void;
    // 存储键名和数据, 注意可能会存在存储已满的情况,这样会抛出异常
    setItem(key: string, value: string): void;
    [name: string]: any;
}

在cocosCreator中,本地数据的存储是以sqlite数据库格式存储的。

我们以setItem简单看下引擎的封装相关:

  • C++相关,目录在: …/engine-native/cocos/storage/local-storage
// LocalStorage.cpp
void localStorageSetItem(const std::string &key, const std::string &value) {
  assert(_initialized);
  int ok = sqlite3_bind_text(_stmt_update, 1, key.c_str(), -1, SQLITE_TRANSIENT);
  ok |= sqlite3_bind_text(_stmt_update, 2, value.c_str(), -1, SQLITE_TRANSIENT);

  ok |= sqlite3_step(_stmt_update);

  ok |= sqlite3_reset(_stmt_update);

  if (ok != SQLITE_OK && ok != SQLITE_DONE)
    printf("Error in localStorage.setItem()\n");
}
  • Android平台相关, 目录在 …/libcocos/intermediates/javac/com/cocos/lib
// LocalStorage-android.cpp
void localStorageSetItem(const std::string &key, const std::string &value) {
  assert(gInitialized);
  JniHelper::callStaticVoidMethod(JCLS_LOCALSTORAGE, "setItem", key, value);
}

// CocosLocalStorage.class 
public static void setItem(String key, String value) {
  try {
    String sql = "replace into " + TABLE_NAME + "(key,value)values(?,?)";
    mDatabase.execSQL(sql, new Object[]{key, value});
  } catch (Exception var3) {
    var3.printStackTrace();
  }
}

简单的看下内部的实现,了解本地数据的存储在数据库中即可。


使用


脚本中使用本地存储,常用的接口是:

  • setItem(key: string, value: string): void; 存储数据

  • getItem(key: string): string | null 获取数据

  • removeItem(key: string): void; 移除数据

简单的示例:

const key = "Debug_Storage";
// 保存数据
sys.localStorage.setItem(key, "cocosCreator");
// 获取数据
let value = sys.localStorage.getItem(key);
console.log("----- 存储的数据是:", value);

注意:

  • setItem存储的数据是string类型,因此存储数据时,注意对数据类型转换
  • setItem的存储存在已满的情况,注意异常的发生
  • getItem获取数据为stringnull, 注意对返回数据的安全判定

因此,在项目中可增加对localStorage的封装管理,以支持:

  1. 支持不同基础数据类型的存储,包括但不限于string类型, 使用数据转换即可

  2. 支持数组、Map等复杂数据类型的存储, 使用 Json 转换

  3. 数据读取,支持默认数据的设置

Json转换的主要接口:

  • JSON.stringify 将数据转换为Json字符串
  • JSON.parse 用于将Json字符串解析为数据

主要实现逻辑如下:

import { _decorator, sys} from 'cc';
const { ccclass, property } = _decorator;

export class StorageManager {
  private static _instance: StorageManager = null;
  static get instance() {
    if (this._instance) {
      return this._instance;
    }
    this._instance = new StorageManager();
    return this._instance;
  }

  // 保存数据
  public setItem(key: string, value:any) {
    if (value === undefined || value === null) {
      console.log(`本地存储数据非法, key:${key}`);
      return;
    }
    let valueType = typeof(value);
    if (valueType === "number" && isNaN(value)) {
      console.log(`本地存储数据为NaN, key:${key}`);
      return;
    } 

    // 转换数据
    if (valueType === "number") {
      value = value.toString();
    } else if (valueType === "boolean") {
      // boolean类型转换为0或1
      value = value ? "1" : "0";
    } else if (valueType === "object") {
      // 数组或Map类型转换为JSON字符串
      value = JSON.stringify(value);
    }
    sys.localStorage.setItem(key, value);
  }

  // 读取数据
  public getItem(key: string, defaultValue: any = ""): any {
    let value = sys.localStorage.getItem(key);
    // 数据获取失败,就走默认设置
    if (value === null) {
      return defaultValue;
    }

    // 检测是否为JSON字符串
    const regex = /^\s*{[\s\S]*}\s*$/;
    if (regex.test(value)) {
      return JSON.parse(value);
    }
    return value;
  }
}

测试用例:

private debugStorage() {
  let storageManager = StorageManager.instance;

  // 检测数据合法性
  storageManager.setItem("Storage_Debug_1", null);
  storageManager.setItem("Storage_Debug_2", undefined);
  storageManager.setItem("Storage_Debug_3", NaN);

  // 存储
  storageManager.setItem("Storage_Int", 10);
  storageManager.setItem("Storage_Boolean", true);
  storageManager.setItem("Storage_Array1", [1,2,3]);
  storageManager.setItem("Storage_Array2", new Array(4,5,6));
  storageManager.setItem("Storage_Map", {name: "TypeScript", index:10});

  // 获取数据
  console.log("Storage_Int", storageManager.getItem("Storage_Int"));
  console.log("Storage_Boolean", storageManager.getItem("Storage_Boolean"));
  console.log("Storage_Array1", storageManager.getItem("Storage_Array1"));
  console.log("Storage_Array2", storageManager.getItem("Storage_Array2"));
  console.log("Storage_Map", storageManager.getItem("Storage_Map"));
}

请添加图片描述

至于 removeItem, key, clear等实现,直接调用localStorage的相关方法即可。


拓展1: 支持保存多份数据


在实际的项目开发中,频繁的功能测试可能需要我们保存多份本地存储数据。

可以通过key键 + 玩家的唯一标识符ID的方式,存储不同用户的数据,以实现保存多份。

StorageManager类的大概修改,可以这样:

// 初始化角色ID, 可用于项目获取用户数据成功后进行设置
private _roleId: string = "";
public setRoleId(id: string) {
	this._roleId = id;
}

// 针对于setItem或getItem的设置,增加如下判定:
let newKey = key;
if (this._roleId !== "") {
  newKey = `${key}_${this._roleId}`;
}
sys.localStorage.setItem(newKey, value);

待定…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1138825.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Security —漏洞防护—跨站请求伪造(CSRF)

在终端用户可以 登录 的应用程序中,必须考虑如何防止 跨站请求伪造(CSRF)。 Spring Security 默认为 不安全的HTTP方法(如POST请求)提供CSRF攻击防护,因此无需额外代码。你可以使用下面的方法明确指定默认…

今年天猫双11,打响电商AI时代第一枪

自阿里提出双11以来,今年已是第15个年头。在这15年间,双11见证了中国电商的发展轨迹,从野蛮生长、完善体验到重质重效。如今,在双11的见证下,中国电商的进化正悄然发生。 一些新的变化值得关注。“最值得买的电视”&a…

系列六、FactoryBean vs ApplicationContext

一、FactoryBean vs ApplicationContext 1.1、概述 BeanFactory是一个工厂类,负责生产和管理bean,在Spring中BeanFactory是IOC容器的核心接口,它的主要职责就是生产bean及建立各个bean之间的依赖。applicationContext是BeanFactory的一个子接…

Go 的连接池、重试和超时

这是一个来自 API 的间歇性 500 个内部服务器错误的故事,这些错误最终是由 Go 包中的硬编码常量引起的database/sql。我将主要为您省去冗长的故事,并直接讨论问题以及我们发现的原因。我们注意到来自特定 API 端点的 500 错误数量有所增加,并…

网络协议--BOOTP:引导程序协议

16.1 引言 在第5章我们介绍了一个无盘系统,它在不知道自身IP地址的情况下,在进行系统引导时能够通过RARP来获取它的IP地址。然而使用RARP有两个问题:(1)IP地址是返回的唯一结果;(2)…

目前最优的非蒸馏、可商用的开源大模型!MIT-IBM 提出鲑鱼模型!

作者 | 谢年年、ZenMoore 今年上半年,IBM 加入大模型战局,提出了一种使用原则(Principle)驱动的、基于 LLM Self-Instruct 的全新方法:SELF-ALIGN (自对齐),并以开源LLaMA为基础,用不到300行&am…

el-table(vue2中)滚动条被固定列盖住

一、项目场景: vue2 el-table 二、问题描述 1、现场图片: 2、全局css环境配置了滚动条高度为6px /* 全局滚动条配置 */ ::-webkit-scrollbar {width: 6px;height: 6px; }::-webkit-scrollbar-track {background-color: #f1f1f1; }::-webkit-scrollbar-…

机器学习2(Numpy)

1、numpy ndarray 案例演示 可以在创建的时候就指定元素类型 生成0/1数组 从现有数组中生成 生成固定数组 生成随机数组

软考系统架构之案例篇(架构设计相关概念)

案例篇-架构设计相关概念 1. 架构风格的概念2. 五大架构风格有哪些3. MVC架构含义4. 云计算架构5. 云原生架构设计原则6. ESB的主要功能包括7. 质量属性的含义及其设计策略8. EJB中的 Bean 分三种类型9. 风险点、敏感点、权衡点的含义10. REST 的5个原则 1. 架构风格的概念 软…

GO 语言的函数

函数是什么? 学过编程的 xdm 对于函数自然不会陌生,那么函数是什么呢? 函数是一段可以重用的代码块,可以被多次调用,我们可以通过使用函数,提高咱们代码代码的模块化,提高程序的可读性和可维护性…

vite vue3 ts 全局封装自定义svg组件,全局引入

1.安装vite-plugin-svg-icons插件 yarn add vite-plugin-svg-icons -D 2.配置vite.config.ts文件,配置插件 import path from path import { createSvgIconsPlugin } from vite-plugin-svg-iconsplugins: [vue(),// 配置svg createSvgIconsPlugin({// 指定需要缓…

如何在Microsoft Visual Studio 中使用Cpp代码调用python代码

Microsoft Visual Studio中Cpp调用Python代码 本文介绍如何在Microsoft Visual Studio中,开发cpp项目时,调用python代码。 文章目录 Microsoft Visual Studio中Cpp调用Python代码前言一、Cpp生成exe文件1.1 安装python环境1.2 配置Microsoft Visual Stu…

vue ant DatePicker 日期选择器 限制日期可控范围

场景 限制当前日期之前不能选择 限制只能选择日期区间内 Ant Design Vue 效果 <a-date-picker :disabledDate"disabledDate"></a-date-picker>method // 限制日期选择disabledDate(current) {return current && current > moment().endOf(&…

JSON parse error: Cannot deserialize instance of `xxx` out of START_ARRAY token

报错原因 前端传参类型是数组&#xff0c;后端接收参数类型是字符串。 解决办法 前端传参类型改为字符串即可。 如下图 【修改前】 【修改后】

【Linux】安装与配置虚拟机及虚拟机服务器坏境配置与连接

目录 操作系统介绍 什么是操作系统 常见操作系统 UNIX操作系统 linux操作系统 mac操作系统 嵌入式操作系统 个人版本和服务器版本的区别 安装VMWare虚拟机 VMWare虚拟网卡 ​编辑 配置虚拟网络编辑器 ​编辑 安装配置Windows Server 2012 R2 安装Windows Server 2…

如何解决电脑中缺失kernel32.dll文件的问题,四种常见的解决方法

在使用电脑过程中&#xff0c;有时我们可能会遇到一些错误提示&#xff0c;例如“找不到或缺少kernel32.dll文件”。遇到这种情况下&#xff0c;我们可以采取哪些措施来解决这个问题呢&#xff1f;本文将介绍关于kernel32.dll文件的作用&#xff0c;并提供四种常见的解决方法。…

拍摄花絮丨《巴渝小将》走进四川·五华山旅游区拍摄圆满成功!

巴渝小将&#xff0c;乘风破浪 本期节目孩子们离开父母&#xff0c;来到五华山旅游区&#xff0c;开启了两天一夜的录制挑战&#xff0c;他们究竟有着怎样的精彩表现呢&#xff0c;让我们一起往下看吧! 五华山旅游区 五华山旅游区是国家4A级旅游景区&#xff0c;位于四川邻水县…

【哈士奇赠书活动 - 44期】- 〖从零基础到精通Flutter开发〗

文章目录 ⭐️ 赠书 - 《从零基础到精通Flutter开发》⭐️ 内容简介⭐️ 作者简介⭐️ 编辑推荐⭐️ 赠书活动 → 获奖名单 ⭐️ 赠书 - 《从零基础到精通Flutter开发》 ⭐️ 内容简介 本书由浅入深地带领读者进入Flutter开发的世界&#xff0c;从Flutter的起源讲起&#xff0c…

Vue前端学习记录

目录 1 基础语法 v-text v-html v-on v-show v-if v-bind 2 简单应用 2.1 计数器 2.1.1所用知识 2.1.2代码及结果展示 2.2图片切换 2.2.1所用知识 2.2.2代码及结果展示 1 基础语法 v-text 设置标签的内容&#xff08;要替换部分字符用差值表达式{{}}&#xff09…

【RTOS学习】软件定时器 | 中断处理

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《RTOS学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 软件定时器 | 中断处理 &#x1f3c0;软件定时器⚽守护任务守护任务的调度 ⚽使用软件定时器的函数…