1、命名空间
命名空间的作用就是将不同的模块按照命名空间分类、隔离,以便更好地组织和管理代码。实际上,命名空间就是将 Vuex store 中的模块对象再次封装,每个模块都有自己的命名空间,在模块内部定义的 state、mutation、action 和 getter 都会注册到模块内部,可以通过带命名空间的形式来访问。
通过引入命名空间,可以解决在多人协作开发时出现的 state 命名冲突等问题,避免了在同一个 Vuex store 中不同模块命名相同的问题,同时还能提高代码的可读性、可维护性和可扩展性。
实际上,命名空间本质上就是一种封装机制,它可以有效地将大的模块拆分为更小的子模块,并提供了更细粒度的权限控制,使得团队成员之间可以更加灵活地分配任务、协作开发。命名空间的引入,不仅可以用于 Vue.js 的 Vuex,也可以用于其他编程领域,例如 JavaScript 的命名空间、Java 的包等等。
总之,命名空间是一种非常有价值和实用的编程概念,它可以提高代码的可读性、可维护性和可扩展性,是多人协作开发中必不可少的工具之一。
调用命名空间时,它的名字与在定义模块时指定的名字一一对应。当在定义 Vuex 模块时,需要在模块对象中设置 namespaced
属性为 true
,这样就会为这个模块开启命名空间。然后,在调用 Vuex actions、mutations、getters、state 等方法时,需要将模块的命名空间作为前缀来使用。
2、命名空间可以由用户自定义命名
命名空间的名字通常是由开发人员自己定义的,用来区分不同的模块。在 Vue.js 的 Vuex 中,需要在定义模块时,设置 namespaced
属性为 true
,表示为该模块开启命名空间。然后,在调用该模块中的 actions、mutations、getters 和 state 时,需要使用模块名作为命名空间的前缀。
例如,在 Vuex store 中定义一个名为 user
的模块,并设置了命名空间:
const store = new Vuex.Store({
modules: {
user: {
namespaced: true, // 开启命名空间
state: {
name: 'Tom'
},
mutations: {
setName (state, payload) {
state.name = payload
},
// 处理其他 mutation
},
actions: {
updateName ({ commit }, payload) {
commit('setName', payload)
},
// 处理其他 action
},
},
// 定义其他模块
},
})
在调用该模块中的 mutation 时,需要在 mutation 的名字前添加该模块的命名空间 user
,例如:
store.commit('user/setName', 'Jerry')
actions、mutations、getters 和 state 时,使用模块名作为命名空间的前缀。这样能有效地避免不同模块内部命名相同的冲突问题,提高代码的可维护性和可读性。
3、indexDB的索引
在IndexedDB中,索引名称和属性名称都是对数据存储和检索过程中很重要的概念。下面我将详细解释一下这两个概念的含义和用法:
- 索引名称
索引名称是指为对象存储空间中的一个属性(或多个属性)创建的索引名称。通过为属性创建索引,我们可以在查询、排序、过滤和更新数据时提高检索效率。对象存储空间中可以创建多个索引,每个索引都有唯一的名称。
例如,我们可以为一个存储用户信息的对象存储空间创建一个名为 "user-store" 的对象存储空间。然后为其创建一个名为 "username" 的索引,这将使得我们可以更快地根据用户名来查询数据记录:
let userIndex = userObjectStore.createIndex("username", "username", {unique: true});
属性名称是指对象存储空间中每个数据记录的各个属性名字。在通过IndexedDB存储和查询数据时,我们需要通过属性名称访问和操作数据记录。例如,如果我们在一个存储用户信息的对象存储空间中创建了一个名为 "username" 的属性,那么我们可以使用它来查询某个用户的信息:
let transaction = db.transaction("user-store", "readwrite");
let userObjectStore = transaction.objectStore("user-store");
let index = userObjectStore.index("username");
let request = index.get("John Doe");
request.onsuccess = function(event) {
// 在这里处理查询结果
};
三个索引
在创建组合索引时,连接索引属性的名称不是固定写法。在示例中,我们使用的是 "usernameAndEmail" 作为组合索引的名称,其中的 "And" 是我们自己定义的名称,并不是必须的。
要创建连接三个属性的组合索引,可以给组合索引一个任意的名称,例如 "usernameEmailCity",然后在创建索引时指定所需的属性。比如:
let store = db.createObjectStore("user", {keyPath: "id"});
store.createIndex("usernameEmailCity", ["username", "email", "city"]);
这样创建的组合索引 "usernameEmailCity" 就连接了三个属性。在进行查询时,可以像之前使用 "usernameAndEmail" 索引一样使用 "usernameEmailCity" 索引,例如:
let transaction = db.transaction("user");
let userStore = transaction.objectStore("user");
let index = userStore.index("usernameEmailCity");
let request = index.get(["john", "john@example.com", "New York"]);
request.onsuccess = function(event) {
let user = event.target.result;
if (user) {
console.log(user);
} else {
console.log("No match found");
}
};
4、数据库的创建
/**
* 打开数据库
* @param {object} dbName 数据库的名字
* @param {string} storeName 仓库名称
* @param {string} version 数据库的版本
* @param {string} priKey 主键
* @param {Object} index 索引
* @return {object} 该函数会返回一个数据库实例
*/
export const openDB = function openDB(dbName, version = 1, storeName, priKey, index=[]) {
// 兼容浏览器
let indexedDB =
window.indexedDB ||
window.mozIndexedDB ||
window.webkitIndexedDB ||
window.msIndexedDB;
let db;
// 打开数据库,若没有则会创建
const request = indexedDB.open(dbName, version);
// 数据库打开成功回调
request.onsuccess = function (event) {
db = event.target.result; // 数据库对象
console.log("数据库打开成功111",db);
resolve(db);
};
// 数据库打开失败的回调
request.onerror = function (event) {
console.log("数据库打开报错",event);
};
// 数据库有更新时候的回调
if (storeName !== undefined) {
request.onupgradeneeded = function (event) {
// 数据库创建或升级的时候会触发
console.log("创建成功!");
db = event.target.result; // 数据库对象
let objectStore;
// 创建存储库
objectStore = db.createObjectStore(storeName, {
keyPath: priKey, // 这是主键
autoIncrement: true // 实现自增
});
// 创建索引,在后面查询数据的时候可以根据索引查
// 首先创建主键对应的索引
objectStore.createIndex(priKey, priKey, {unique: true});
for (let i = 0; i < index.length; i++) {
// 然后创建主要索引
objectStore.createIndex(index[i], index[i], {unique: false});
}
};
}
});
在此回调函数中,将 event.target.result
赋值给变量 db
,表示获得了打开的数据库实例对象。最后,将该实例对象作为异步回调中的参数传入 resolve
中,以便其他模块可异步获取该实例对象。
若打开数据库失败,则会调用 request.onerror
回调函数,会将错误信息打印输出到控制台。
若需要在打开或创建数据库时,指定需要创建的数据仓库名称(storeName
),则需设置 request.onupgradeneeded
回调函数。该回调函数会在数据库创建或升级时触发。
在该函数中,首先判断是否需要创建数据仓库,若需要,则设置 request.onupgradeneeded
回调函数。在该回调函数中,获取打开或创建的数据库实例对象,接着根据需要,创建存储库(即数据仓库)db.createObjectStore
,并设置主键和自增属性。最后,根据 index
中的定义创建索引对象。这些操作会在创建数据库或升级数据库版本时执行。
在最后,该函数通过 Promise
实例,将打开或创建的数据库实例对象返回给调用方。因此,使用该函数时,需要使用 then
方法或 async/await
等方式异步获取该实例对象,并使用该实例对象进行 IndexedDB 操作。
5、数据库名和仓库
数据仓库(Database)是指 IndexedDB 中的一个数据容器,用于存储和管理多个对象存储空间(ObjectStore),相当于关系型数据库中的数据库(Database),而对象存储空间则相当于其中的数据表(Table)。每个数据仓库都有一个唯一名称,并包含多个对象存储空间,每个对象存储空间又包含若干记录(Record)。
数据库名称和仓库名称是 IndexedDB 中的两个不同概念,其区别如下:
- 数据库名称:是指整个 IndexedDB 数据库的名称,表示要创建或打开的数据库的名称,用于标识数据存储容器的唯一名称。
- 仓库名称:是指数据库中的对象存储空间的名称,表示为数据存储容器中的若干对象存储空间命名,用于存储和管理数据,每个对象存储空间都有自己的名称和一组可选的索引。
因此,一个 IndexedDB 数据库中可以包含多个不同名称的对象存储空间,这些对象存储空间可以有相同或不同的结构,用于存储和管理不同类型的数据。在同一个 IndexedDB 数据库中,可以存在多个仓库,且仓库名称可以相同。
需要注意的是,虽然同一浏览器中的不同 IndexedDB 数据库的名称可以相同,但它们实际上是不同的数据库,存储的数据也是独立的。这是因为 IndexedDB 数据库的唯一标识符是由数据库名称、版本号和安全来源三个部分组成的。如果数据库名称和版本号一致,但安全来源不同,仍然会构成不同的数据库。因此,在实际使用中,建议不要使用相同的数据库名称,以避免混淆和错误。