65.9K
CodeProject 正在变化。 阅读更多。
Home

HTML 5 离线数据库(indexedDB 和 WebSql)的非常简单的示例

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (20投票s)

2014 年 9 月 18 日

CPOL

4分钟阅读

viewsIcon

152577

downloadIcon

7869

本文介绍了在处理 HTML 5 离线应用程序时用于在数据库(indexedDB 和 WebSql)中创建、编辑、修改或删除表数据的浏览器数据库的基本知识。

引言

此应用程序仅供参考,而非教学。我在这篇文章中与我一样的初学者分享了我代码的一小部分。我将很高兴收到您的建议或任何评论。

本文试图解释浏览器数据库的基本知识,这在处理 HTML 5 离线应用程序时非常有用。开发者如何开发一个能够与浏览器本地数据库交互、插入新记录、修改或编辑表中现有记录、获取表中的所有记录或特定记录以及删除表中记录的 Web 应用程序。

背景

为了使我们的 Web 应用程序能够离线工作,我们需要两样东西:

  • CACHE.APPCACHE:将所有必需的文件(HTML 页面、JavaScript 文件、图像等)获取到本地浏览器
  • DATABASE:用于在本地存储用户工作数据的数据库

CACHE.APPCACHE

第一点可以使用 HTML 5 的一个新功能 `cache.appcache` 文件来实现。您可以轻松找到关于 `cache.appcache` 文件的有用教程,并且使用此文件实现缓存非常容易。对于我们的项目,我们不会编写一个硬编码的文件,在这个项目中,我们将实现一个将作为此文件服务器的 **Action Result**。

数据库

现在这是本文最重要的部分。任何应用程序都需要数据库来存储信息/记录,就像服务器端的 SQL Server 一样。由于我们正在实现一个离线应用程序,我们需要一个数据库来存储信息/记录。对于离线应用程序,不同的浏览器支持两种类型的数据库。

  • WebSql 适用于 Safari 类浏览器
  • IndexedDB 适用于 Mozilla、Chrome、Internet Explorer 类浏览器。

WebSql:这是一个基于查询的数据库,类似于 SQL Server。您需要像在 SQL Server 中一样编写查询来插入更新删除记录。此数据库用于 Safari 浏览器。

IndexedDB:这个数据库基于对象,我们不需要为它编写查询。它只是用于添加更新删除对象。对于这个数据库,我们将使用 Aaron Powell 提供的一个 `db.js` 包装文件。我们将此数据库用于 Safari 浏览器以外的所有浏览器。

Using the Code

缓存清单 Action 的实现

// Cache Action
public ActionResult Manifest()
     {
         var manifest = "CACHE MANIFEST" + Environment.NewLine +
            "# App Version: " + System.IO.File.GetLastWriteTime
            (Server.MapPath("~/Views/Home/Index.cshtml")) + Environment.NewLine +
            "# Server Assembly Version: " + this.GetType().Assembly.GetName().Version + 
        Environment.NewLine +
            "NETWORK:" + Environment.NewLine +
            "*" + Environment.NewLine +
            "CACHE:" + Environment.NewLine +
            Url.Action("Index", "Home") + Environment.NewLine +
            Url.Content("~/Content/site.css") + Environment.NewLine +
            Url.Content("~/Content/bootstrap.min.css") + Environment.NewLine +
            Url.Content("~/scripts/jquery-1.7.1.js") + Environment.NewLine +
            Url.Content("~/scripts/bootstrap.min.js") + Environment.NewLine +
            Url.Content("~/scripts/bootbox.min.js") + Environment.NewLine +
            Url.Content("~/scripts/db.js") + Environment.NewLine +
            Url.Content("~/scripts/Config.js") + Environment.NewLine +
            Url.Content("~/scripts/DbManager.js") + Environment.NewLine +
            Url.Content("~/scripts/index.js") + Environment.NewLine +
            Url.Content("~/scripts/jquery.blockUI.js") + Environment.NewLine +
            Url.Content("~/scripts/cache.js") + Environment.NewLine;

         return Content(manifest, "text/cache-manifest");
    }

这个 `Action` 结果包含三行主要代码。

这行代码设置了 `cache.appcache` 文件的版本。每当您更改主视图中的任何内容时,这将强制浏览器从服务器获取新文件。

"# App Version: " + System.IO.File.GetLastWriteTime
            (Server.MapPath("~/Views/Home/Index.cshtml")) + Environment.NewLine +

要添加新文件,可以使用这行代码添加文件:

Url.Content("~/Content/site.css") + Environment.NewLine +

此 Action 的返回类型设置为“text/cache-manifest”类型。

return Content(manifest, "text/cache-manifest");

现在,要将此清单添加到您的布局或页面,只需将此行添加到您的页面 `html` 标记中。

html manifest="@Url.Action("Manifest", "Home")"

好了,缓存清单代码就完成了。

数据库的实现

现在我们将有两个代码块部分,一个用于 `websql`,另一个用于 `indexedDb`。首先,我们需要识别它是否是 Safari 浏览器。如果是 Safari 浏览器,我们将使用 `websql`,否则使用 `indexedDB`。

if (navigator.userAgent.indexOf("Safari") >= 0 
&& navigator.userAgent.indexOf("Chrome") < 0) {
    //SAFARI BROWSER SO WEBSQL IMPLEMENTATION HERE
}else{
    //OTHER BROWSERS SO INDEXEDDB IMPLEMENTATION HERE
}

现在,我们需要初始化我们的数据库。

if (navigator.userAgent.indexOf("Safari") >= 0 
&& navigator.userAgent.indexOf("Chrome") < 0) {
    var DataBaseManager = {
            Offlinedb: openDatabase("OfflineDB", '1', 'my first database',
            2 * 1024 * 1024)//this accept four parameters 1. database name,
 //2. version, 3. Comments, 4.initial Size
    }
}else{
    //For indexedDB the db.js file automatically initialize the database.
    //So we just need to provide the schema and database name during our database operations.
}

现在,在继续之前,我们首先将为 `indexedDB` 声明一个全局 schema 对象,其中包含一个 `UserData` 表,`UserID` 设置为 `true`(自动递增)。

var OfflineConfiguration = {
    Db_VERSION: 1,
    DB_NAME: "OfflineDB",
    SCHEMA: {
        UserData: { key: { keyPath: 'UserID', autoIncrement: true } }
    }
};

现在我们有了一个用于存储应用程序数据库的数据服务器,我们需要定义数据库的 schema。对于 `WebSql`,我们将使用查询来定义表结构,对于 `IndexedDb`,我们将使用对象来定义 schema。我们的应用程序使用单个表,即 `UserData`,而 `UserID` 是一个自动递增的标识列。

if (navigator.userAgent.indexOf("Safari") >= 0 
&& navigator.userAgent.indexOf("Chrome") < 0) {
    var DataBaseManager = {
            Offlinedb: openDatabase("OfflineDB", '1', 'my first database', 2 * 1024 * 1024),
        initializeDataBase: function () {
                    var self = this;
                    self.Offlinedb.transaction(function (tx) {
                        tx.executeSql('CREATE TABLE IF NOT EXISTS UserData
                        (UserID INTEGER PRIMARY KEY AUTOINCREMENT, Name, Email, Technology)');
                    });
            },
    }
}else{
    var DataBaseManager = {
        //For indexedDB we will not have any initialize function 
        //as we already define the schema for this globally.
    }
}

数据操作

现在,我们有了表,就可以进行数据操作了:`ADD`(添加)、`GET`(获取)、`UPDATE`(更新)和 `DELETE`(删除)。

1. 添加用户

if (navigator.userAgent.indexOf("Safari") >= 0 
&& navigator.userAgent.indexOf("Chrome") < 0) {
    var DataBaseManager = {
            Offlinedb: openDatabase("OfflineDB", '1', 'my first database', 2 * 1024 * 1024),
        initializeDataBase: function () {
                    var self = this;
                    self.Offlinedb.transaction(function (tx) {
                        tx.executeSql('CREATE TABLE IF NOT EXISTS UserData
                        (UserID INTEGER PRIMARY KEY AUTOINCREMENT, Name, Email, Technology)');
                    });
            },
        AddnewUser: function (data, callback) {//data: contains the object of user ,
                        // callback: is a function will execute after the addition

                    this.initializeDataBase();
                    var self = this;
                    self.Offlinedb.transaction(function (tx) {
                        var query = "insert into UserData(Name,Email,Technology) values(?,?,?)";
                        tx.executeSql(query, [data.Name, data.Email, data.Technology], 
            function (tx, results) {
                                if (callback) callback("User Saved");
                        });
                    });
            }
    }
}else{
    var DataBaseManager = {
        //For indexedDB we will not have any initialize function as we already define 
        //the schema for this globally.
        AddnewUser: function (data, callback) {//data: contains the object of user ,
                    // callback: is a function will execute after the addition
                    db.open({
                        server: OfflineConfiguration.DB_NAME,//database name defined globally
                        version: OfflineConfiguration.Db_VERSION,//version defined globally
                        schema: OfflineConfiguration.SCHEMA//schema defined globally

                    }).done(function (s) {
                        self.Server = s;
                        self.Server.UserData.add(data).done(function (results) {
                                if (callback) callback("Data added into UserData");
                        });
                    });
            },
    }
}

2. 获取用户

if (navigator.userAgent.indexOf("Safari") >=0 
&& navigator.userAgent.indexOf("Chrome") < 0) {
    var DataBaseManager = {
            .....
        GetSingleUser: function (data, callback) {//data: contains the UserID ,
                // callback: is a function will execute after the selection
                    try {
                        var self = this;
                        this.initializeDataBase();
                        var query1 = "SELECT * from UserData where UserID=" + data;
                        self.Offlinedb.transaction(function (tx) {
                                tx.executeSql(query1, [], function (tx, results) {
                                    if (results.rows.length > 0) {
                                            var v = results.rows.item(0);
                                            if (callback) callback(results.rows.item(0));
                                    } else {
                                            if (callback) callback("Not Found");
                                        }
                                });
                        });

                    }
                    catch (e) {
                        console.log(" error occurred in selecting data");
                    }
            },

        ....
    }
}else{
    var DataBaseManager = {
        ....
        GetSingleUser: function (data, callback) {//data: contains the UserID ,
                //callback: is a function will execute after the selection
                    db.open({
                        server: OfflineConfiguration.DB_NAME,
                        version: OfflineConfiguration.Db_VERSION,
                        schema: OfflineConfiguration.SCHEMA

                    }).done(function (s) {
                        self.Server = s
                        self.Server.UserData
                               .query()
                            .all()
                            .filter(function (result) {
                                    return result.UserID === parseInt(data);
                            })
                            .execute()
                            .done(function (finalResult) {
                                    if (callback) callback(finalResult);
                            });
                    });
            },
        ....

    }
}

3. 更新用户

if (navigator.userAgent.indexOf("Safari") >=0 
&& navigator.userAgent.indexOf("Chrome") < 0) {
    var DataBaseManager = {
            .....
        UpdateUser: function (data, callback) {//data: contains the object of user ,
                // callback: is a function will execute after the updation
                    try {
                        this.initializeDataBase();
                        var self = this;
                        var query1 = "update UserData set Name=?,Email=?,Technology=? where UserID=?";
                        self.Offlinedb.transaction(function (tx) {
                                tx.executeSql(query1, [data.Name, data.Email,
                                data.Technology, parseInt(data.UserID)], function (tx, results) {
                                    if (callback) callback("Response updated");
                                });
                        });

                    }
                    catch (e) {
                        console.log(" error occurred in selecting data");
                   }
            },

        ....

    }
}else{
    var DataBaseManager = {
        ....
        UpdateUser: function (data, callback) {//data: contains the object of user ,
                // callback: is a function will execute after the updation
                    db.open({
                        server: OfflineConfiguration.DB_NAME,
                        version: OfflineConfiguration.Db_VERSION,
                        schema: OfflineConfiguration.SCHEMA

                    }).done(function (s) {
                        self.Server = s
                        self.Server.UserData.update(data).done(function (item) {
                                if (callback) callback("response updated to database");
                        });
                    });
            },

        ....

    }
}

4. 删除用户

if (navigator.userAgent.indexOf("Safari") >=0 
&& navigator.userAgent.indexOf("Chrome") < 0) {
    var DataBaseManager = {
            .....
        DeleteUser: function (data, callback) {//data: contains the UserID of user ,
                    // callback: is a function will execute after the deletion
                    try {
                        this.initializeDataBase();
                        var self = this;
                        self.Offlinedb.transaction(function (tx) {
                                tx.executeSql("Delete from UserData where UserID=?", 
                [data], function (tx, results) {
                                    if (callback) callback("Data deleted");
                                });
                        });

                    }
                    catch (e) {
                    }
            }

        ....

    }
}else{
    var DataBaseManager = {
        ....
        DeleteUser: function (data, callback) {//data: contains the UserID of user ,
                // callback: is a function will execute after the deletion
                    var self = this;
                    db.open({
                        server: OfflineConfiguration.DB_NAME,
                        version: OfflineConfiguration.Db_VERSION,
                        schema: OfflineConfiguration.SCHEMA

                    }).done(function (s) {
                        self.Server = s
                        self.Server.UserData.remove(data).done(function (a) {
                                if (callback) callback("Data deleted");
                        });
                    });
            }

        ....

    }
}

好了!我们完成了四种数据操作。

这些操作的用途

您可以参考 `index.js` 文件,其中我实现了这些操作的用法。

1. 添加新用户操作的用法

    var data = '{"Name":"Vinu","Email":"itvinay12@gmail.com",
"Technology":".NET"}';//user object
        data = JSON.parse(data);
        DataBaseManager.AddnewUser(data, GetAllUser);// GetAllUser is a 
                //function defined in index.js you can refer it.

2. 获取用户操作的用法

DataBaseManager.GetSingleUser(1, anycallbackfunction);// Get the details of user with id 1.

3. 更新用户操作的用法

    var data = '{"UserID":1,"Name":"Vinu",
"Email":"itvinay12@gmail.com","Technology":".NET"}';//user object  with UserID
        data = JSON.parse(data);
        DataBaseManager.UpdateUser(data, GetAllUser);// GetAllUser is a 
                //function defined in index.js you can refer it.

4. 删除用户操作的用法

        DataBaseManager.DeleteUser(1,GetAllUser);// delete the details of user with id 1.

关注点

我只想建议一点:在开始这类应用程序之前,请选择最好的 JavaScript 框架,并阅读有关浏览器兼容性的信息。

历史

  • 2014年9月18日:首次发布
© . All rights reserved.