JsStore是IndexedDB的包装器。它提供了简单的SQL,如api,易于学习和使用。IndexedDb查询可以在web worker中执行,JsStore通过提供一个单独的worker文件来保留这个功能。
Insert API用于在表中插入新记录,还可以为未在db模式中定义的列插入数据。JsStore保留了IndexedDb的NoSql功能。
insert API参数配置:
属性 | 描述 |
---|---|
into | 用于指定表的名称 |
values | 用于指定要插入的数据。它接受一个数据数组。 |
return | 是一个可选的&类型的布尔字段。它用于获取插入的数据。 |
upsert | 如果存在则更新数据,否则插入。默认值为false。 |
validation | 是否验证数据。缺省值为true。这可以用来加速插入查询。 |
skipDataCheck | 不要检查或更改数据中的任何内容。缺省值为false。 如果提供true,这将直接插入数据,而不检查任何东西,如数据类型,自动增量等。这在你想要一次插入大量记录并且对模式没有任何约束的情况下是有用的。 |
ignore | 发生错误时忽略记录。当您从用户或任何来源接收一些随机数据时。 |
一、搭建Demo
首先还是搭建一个学生列表演示Demo,用来获取学生列表及新增功能页面。
1.1 安装
vue-cli全局安装
npm install -g vue-cli
初始化项目
vue init webpack example
其他插件就不细讲了,可以查看:https://blog.csdn.net/jiciqiang/article/details/115792838目录一、vue安装二、sass安装三、vuex安装四、vue-devtolls安装五、vue-ls安装一、vue安装1.vue-cli全局安装npm install -g vue-cli2.初始化项目vue init webpack projectName3.运行项目注:npm中-g, -d, -s区别1.-g 全局安装,全称--global2.-s 安装到dependencies中,用于生产环境,即--save3.-d 安装到devD.https://blog.csdn.net/jiciqiang/article/details/115792838
1.2 页面创建
在src/pages/index目录中创建index.vue,代码如下:
<template>
<div class="jsstore-insert-wrap">
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="姓名">
<el-input size="small" v-model="formData.name" placeholder="请输入姓名"></el-input>
</el-form-item>
<el-form-item label="年级">
<el-input size="small" v-model="formData.grade" placeholder="请输入年级"></el-input>
</el-form-item>
<el-form-item label="地址">
<el-input size="small" v-model="formData.address" placeholder="请输入地址"></el-input>
</el-form-item>
<el-form-item label="生日">
<el-date-picker
size="small"
v-model="formData.birthday"
type="date"
placeholder="选择生日">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary">新增</el-button>
</el-form-item>
</el-form>
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="grade" label="年级"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column prop="birthday" label="生日"></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data(){
return {
formData: {
name: "",
grade: "",
address: "",
birthday: ""
},
tableData: []
}
},
created() {
this.updateList();
},
methods: {
/**
* 获取学生列表
*/
updateList(){
},
//end
}
}
</script>
<style lang="scss">
@import './index.scss';
</style>
在src/router/index.js中,添加路由,代码如下:
import Vue from 'vue'
import Router from 'vue-router'
import Index from '@/pages/index'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Index',
component: Index
}
]
})
此时页面效果如下:
二、初始化数据结构
页面基本结构完成后,现在开始创建数据表结构。首先,在src下创建db目录,新建db/db.js用于实例并连接数据库,新建db/service.js用于定义表结果和表结构初始化。
db.js代码如下:
import { Connection } from "jsstore";
import workerInjector from "jsstore/dist/worker_injector";
let connection = new Connection();
connection.addPlugin(workerInjector);
export default connection;
service.js代码如下:
import connection from './db.js';
import { DATA_TYPE } from "jsstore";
export const DATA_TABLE_NAME = {
STUDENT: "Student",
}
/**
* 实例化数据表
*/
const getDatabase = () => {
//学生表
const tbStudent = {
name: DATA_TABLE_NAME.STUDENT,
columns: {
id: { primaryKey: true, autoIncrement: true },
name: { notNull: true, dataType: DATA_TYPE.String },
grade: { notNull: true, dataType: DATA_TYPE.String },
birthday: { notNull: true, dataType: DATA_TYPE.DateTime },
address: { notNull: false, dataType: DATA_TYPE.String },
createtime: { notNull: true, dataType: DATA_TYPE.DateTime },
updatetime: { notNull: true, dataType: DATA_TYPE.DateTime },
}
}
const dataBase = {
name: "DemoTestSystem",
tables: [tbStudent],
version: 1
};
return dataBase;
}
/**
* 初始化数据库
*/
export const initJsStore = async () => {
const dataBase = await getDatabase();
return await connection.initDb(dataBase);
}
此时在App.vue中,初始化数据表,如果表已存在,则不会再次创建。代码如下:
import { initJsStore } from '@/db/service.js'
export default {
name: 'App',
data(){
return {
}
},
async beforeCreate(){
try {
const isDbCreated = await initJsStore();
if (isDbCreated) {
console.log("db created");
} else {
console.log("db opened");
}
} catch (ex) {
this.$message.error(ex.message);
}
}
}
当执行npm run dev运行项目后,F12打开控制台,切换到Application项中查看IndexedDB,会发现定义的表已创建,如下图:
三、查询数据列表
这次我们先将列表数据查询功能完成,在src/db目录下,再创建一个model目录,用于存储student.js数据表操作文件。代码如下:
/**
* 学生表
*/
import connection from '@/db/db.js'
import { DATA_TABLE_NAME } from '@/db/service.js'
class StudentService {
constructor(){
this.tableName = DATA_TABLE_NAME.STUDENT;
}
/**
* 获取学生数据列表
*/
selectData(){
return connection.select({
from: this.tableName
})
}
}
export const Student = new StudentService();
上面已将查询数据列表的selectData()函数定义好了,我们可以在pages/index/index.vue页面中调用了,代码如下:
import { Student } from '@/db/model/student'
export default {
data(){
return {
formData: {
name: "",
grade: "",
address: "",
birthday: ""
},
tableData: []
}
},
created() {
this.updateList();
},
methods: {
/**
* 获取学生列表
*/
updateList(){
Student.selectData().then(res => {
this.tableData = res;
})
},
//end
}
}
以上步骤完成后,页面还是没有任何数据,这是我们还没有插入数据。
四、参数用法
Insert API以下选项,在不同情况下,可以使用对应属性得到自己想要的结果。
4.1 基本用法
先使用 into 和 values 属性完成数据插入操作,在StudentService类中,创建insertData()函数,代码如下:
class StudentService {
constructor(){
this.tableName = DATA_TABLE_NAME.STUDENT;
}
/**
* 获取学生数据列表
*/
selectData(){
return connection.select({
from: this.tableName
})
}
/**
* 执行数据
* @param {Object} data
*/
insertData(data){
//添加记录时间
if('undefined'!==typeof data['id']){
Object.assign(data, {
updatetime: new Date()
})
}else{
Object.assign(data, {
createtime: new Date(),
updatetime: new Date()
})
}
return connection.insert({
into: this.tableName,
values: [data]
});
}
}
在页面中新增按钮添加点击事件,完成数据提交操作,代码如下:
<el-form-item>
<el-button size="small" type="primary" @click="submitEvent">新增</el-button>
</el-form-item>
methods中添加submitEvent()事件,当执行数据成功后,重新获取列表数据,调用updateList()函数,代码如下:
methods: {
/**
* 提交数据
*/
submitEvent(e){
Student.insertData(this.formData).then(res => {
console.log('success', res);
this.updateList();
});
},
/**
* 获取学生列表
*/
updateList(){
Student.selectData().then(res => {
this.tableData = res;
})
},
//end
}
写用这里,我们可以在页面填入学生信息,进行数据插入操作了。如下图操作,点击新增保存学生信息,则Student表中则执行一条数据,控制台也返回success 1,即成功执行1条数据。
4.2 显示生日
在上面操作中,发现生日并未显示出来,这是存储的生日数据类型为Date,此时我们需要将其转化成字符串进行显示。
table中稍作修改,为其添加formatDate过滤器,代码如下:
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="grade" label="年级"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column prop="birthday" label="生日">
<template slot-scope="scope">
<span>{{scope.row.birthday | formateDate}}</span>
</template>
</el-table-column>
</el-table>
定义formateDate过滤函数,代码如下:
export default {
data(){
return {
formData: {
name: "",
grade: "",
address: "",
birthday: ""
},
tableData: []
}
},
filters: {
//格式化日期
formateDate(val){
return (date => {
return `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}`;
})(new Date(val));
}
},
//略...
}
此时页面中生日则显示出来了,如下图:
4.3 返回新增数据
在上面操作中会发现,不借助其他属性情况下,插入新数据成功后,只会返回执行成功几条数据,并不会返回新增数据结果。这在有些情况下,程序需要知道新插入数据生成的id等相关数据,此时我们只要insert中添加 return属性即可。代码如下:
insertData(data){
//添加记录时间
if('undefined'!==typeof data['id']){
Object.assign(data, {
updatetime: new Date()
})
}else{
Object.assign(data, {
createtime: new Date(),
updatetime: new Date()
})
}
return connection.insert({
into: this.tableName,
values: [data],
return: true
});
}
此时再添加一条数据,控制台返回了插入成功的数据,并带回了递增的ID值,结果如下:
4.4 覆盖存在数据
首先我们先将src/pages/index/index.vue文件进行改造下,让其能进行编辑操作,代码如下:
<template>
<div class="jsstore-insert-wrap">
<el-form :inline="true" class="demo-form-inline">
//略...
<el-form-item>
<el-button size="small" type="primary" @click="submitEvent">{{!formData.id||formData.id==0?'新增':'保存'}}</el-button>
<el-button size="small" type="info" @click="cancelEvent" v-if="formData.id&&formData.id>0">取消编辑</el-button>
</el-form-item>
</el-form>
<el-table :data="tableData" style="width: 100%">
//略...
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="primary" size="small" icon="el-icon-edit" circle @click="editEvent(scope.row)"></el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import { Student } from '@/db/model/student'
export default {
data(){
return {
formData: {
name: "",
grade: "",
address: "",
birthday: ""
},
tableData: []
}
},
//略...
methods: {
/**
* 提交数据
*/
submitEvent(e){
Student.insertData(this.formData).then(res => {
console.log('success', res);
this.updateList();
});
},
/**
* 编辑事件
*/
editEvent(data){
this.formData = data;
},
cancelEvent(){
this.formData = {
name: "",
grade: "",
address: "",
birthday: ""
}
},
/**
* 获取学生列表
*/
updateList(){
Student.selectData().then(res => {
this.tableData = res;
})
},
//end
}
}
</script>
此时,我们点击编辑按钮,修改内容中生日进行保存操作,会报”Key already exists in the object store.“错误,这是因为编辑保存时,里面带入了id自递值已存在。所以这时需要设置upsert,将其置为true表示覆盖原数据。如下图:
我们将insert中添加upsert,则可以正常保存数据了。代码如下:
insertData(data){
//添加记录时间
if('undefined'!==typeof data['id']){
Object.assign(data, {
updatetime: new Date()
})
}else{
Object.assign(data, {
createtime: new Date(),
updatetime: new Date()
})
}
return connection.insert({
into: this.tableName,
values: [data],
return: true,
upsert: true
});
}
此时修改数据保存后,则不会报错了。页面效果如下:
当然,编辑操作,建议使用update API进行处理,这里只是演示下,通过insert也可以完成编辑操作。
4.5 验证数据
validation是否验证数据。缺省值为true。这可以用来加速插入查询。当validation为false时,它只检查和更新:autoincrement和默认值。
当validation默认为true时,我们在填写信息时,将生日漏填,直接点击保存,则控制台会报”Supplied value for column 'birthday' have wrong data type“错误。
我们将validation设置为false,代码如下:
insertData(data){
//添加记录时间
if('undefined'!==typeof data['id']){
Object.assign(data, {
updatetime: new Date()
})
}else{
Object.assign(data, {
createtime: new Date(),
updatetime: new Date()
})
}
return connection.insert({
into: this.tableName,
values: [data],
return: true,
upsert: true,
validation: false
});
}
此时生日信息不填写,点击保存则不会再报错了。效果如下图:
4.6 跳过数据检查
不要检查或更改数据中的任何内容。缺省值为false。如果提供true,这将直接插入数据,而不检查任何东西,如数据类型,自动增量等。这在你想要一次插入大量记录并且对模式没有任何约束的情况下是有用的。
validation和skipDataCheck之间的区别是,validation为autoIncrement列和默认值生成autoIncrement字段,但skipDataCheck不改变数据中的任何内容,则主键自增也会失效。
如果我们将skipDataCheck置为true,代码如下:
insertData(data){
//添加记录时间
if('undefined'!==typeof data['id']){
Object.assign(data, {
updatetime: new Date()
})
}else{
Object.assign(data, {
createtime: new Date(),
updatetime: new Date()
})
}
return connection.insert({
into: this.tableName,
values: [data],
return: true,
upsert: true,
skipDataCheck: true
});
}
如下图所示,页面会报错”Failed to execute 'put' on 'IDBObjectStore': Evaluating the object store's key path did not yield a value.“,主键则无法自动生成。
注:建议不要使用skipDataCheck,如果你有自动增量字段,否则你的自动增量数据可能无法与插入的数据同步,并可能产生问题。
4.7 ignore
发生错误时忽略记录。当您从用户或任何来源接收一些随机数据时,这很有帮助。
例:假设你有5行,其中3行无效。它可以是-空值,数据类型不匹配,主键的现有值等。然后将插入2行,其中3行将被忽略。所以结果是2。
缺省情况下,ignore值为false。因此,当任何错误发生时,您将得到错误&整个事务被中止。
我们将ignore置为true,代码如下:
insertData(data){
//添加记录时间
if('undefined'!==typeof data['id']){
Object.assign(data, {
updatetime: new Date()
})
}else{
Object.assign(data, {
createtime: new Date(),
updatetime: new Date()
})
}
return connection.insert({
into: this.tableName,
values: [data],
return: true,
upsert: true,
ignore: true
});
}
此时我们在页面中新增数据,将生日缺失,点击保存后,控制台不会报任何错误,并且可以正常返回结果,且为空数组,表示插入数据失败。
这里Insert API的选项就已讲完了,希望对大家有所帮助。