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

使用 MEAN Stack 创建联系人管理器应用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (11投票s)

2017年2月6日

CPOL

5分钟阅读

viewsIcon

40333

使用 MEAN Stack 创建联系人管理器应用程序

引言

MEAN堆栈是一项可用于开发Web应用程序的技术,MEAN是由MongoDB、ExpressJS、AngularJS和NodeJS组成的堆栈。借助MEAN堆栈,我们可以获得开发完整应用程序的所有组件。

  • MongoDB:数据库
  • ExpressJS:RESTful API
  • AngularJS:演示
  • NodeJS:JavaScript服务器端

技能前提

  • JavaScript
  • 数据库概念
  • 命令行

软件先决条件

  • NodeJS
  • MongoDB
  • 文本编辑器(VS Code、Vim等)

Using the Code

步骤01 - 环境设置

为了能够使用本指南,我们需要安装NodeJS,因此请访问此链接下载最新版本的NodeJS。下载完成后,运行安装程序,按照步骤操作,安装完成后,打开命令行终端并测试以下命令:node -v,该命令显示NodeJS版本,在我这里显示的是v5.9.1

接下来安装MongoDB,从MongoDB下载中心下载安装程序,安装并按照安装向导中的步骤进行操作。在我这里,安装目录是:C:\Program Files\MongoDB\Server\3.2\bin,我们可以使用mongod命令启动MongoDB服务,您将看到类似如下的输出:

MongoDB Command Line

关于ExpressJS和AngularJS,我们可以通过NPM从命令行安装它们,NPM是Node包管理器,我们也可以卸载包。例如,如果我们想安装这两个包,我们可以在命令行中输入以下命令:

  • npm install angular
  • npm install express

如果我们输入npm install,NPM将使用package.json文件来知道要安装哪些包。如果您不知道如何编写package.json的内容,只需在命令行中输入npm init并提供项目信息即可。

步骤02 - 添加代码

环境设置完成后,我们将使用MEAN堆栈创建一个联系人管理器应用程序,我们继续打开命令行并按照以下步骤操作:

  1. 创建一个名为ContactManager.Mean的目录
  2. 切换到新目录
  3. 执行此命令:npm init并为您的项目提供信息
  4. package.json文件中添加body-parse
  5. package.json文件中添加express
  6. package.json文件中添加mongojs
  7. 保存更改并恢复包

我们的package.json文件如下:

{
  "name": "contactmanager",
  "version": "1.0.0",
  "description": "Contact Manager App developed with MEAN Stack",
  "main": "server.js",
  "dependencies": {
    "body-parser": "^1.10.2",
    "express": "^4.11.1",
    "mongojs": "^0.18.1"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/hherzl/ContactManager.Mean.git"
  },
  "author": "C. Herzl",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/hherzl/ContactManager.Mean/issues"
  },
  "homepage": "https://github.com/hherzl/ContactManager.Mean#readme"
}

现在,我们将继续创建一个名为Server.js的文件,其中包含以下代码:

var express = require("express");
var bodyParser = require("body-parser");

var app = express();
app.use(express.static(__dirname + "/public"));
app.use(bodyParser.json());

var rest = require("./api");
var api = new rest(app);

var port = 3000;

app.listen(port);

console.log("Server running on port " + port);

api.js代码文件

function api (app) {
    var mongojs = require("mongojs");
    
    var db = mongojs("contactManager", ["contacts"]);

    app.get("/api/contact", function (request, response) {
        var pageSize = request.query.pageSize ? parseInt(request.query.pageSize) : 10;
        var firstName = request.query.firstName;
        var middleName = request.query.middleName;
        var lastName = request.query.lastName;

        var find = {};

        if (firstName) {
            find.firstName = new RegExp(firstName, "i");
        }

        if (middleName) {
            find.middleName = new RegExp(middleName, "i");
        }

        if (lastName) {
            find.lastName = new RegExp(lastName, "i");
        }

        var fields = {
            firstName: 1,
            middleName: 1,
            lastName: 1,
            phone: 1,
            email: 1
        };

        var result = db.contacts.find(find, fields).limit
                     (pageSize, function (err, docs) {
            response.json(docs);
        });
    });

    app.get("/api/contact/:id", function (request, response) {
        var id = request.params.id;

        db.contacts.findOne({ _id: mongojs.ObjectId(id) }, function (err, doc) {
            if (err)
                console.log("Error: " + err);

            response.json(doc);
        });
    });

    app.post("/api/contact", function (request, response) {
        db.contacts.insert(request.body, function (err, doc) {
            if (err)
                console.log("Error: " + err);

            response.json(doc);
        });
    });

    app.put("/api/contact/:id", function (request, response) {
        var id = request.params.id;

        db.contacts.findAndModify({
            query: {
                _id: mongojs.ObjectId(id)
            },
            update: {
                $set: {
                    firstName: request.body.firstName,
                    middleName: request.body.middleName,
                    lastName: request.body.lastName,
                    phone: request.body.phone,
                    email: request.body.email
                }
            },
            new: true
        }, function (err, doc) {
            response.json(doc);
        });
    });

    app.delete("/api/contact/:id", function (request, response) {
        var id = request.params.id;

        db.contacts.remove({ _id: mongojs.ObjectId(id) }, function (err, doc) {
            if (err)
                console.log("Error: " + err);

            response.json(doc);
        });
    });
};

module.exports = api;

server.js文件的开头,我们使用require函数加载所有依赖项,然后我们使用app.use(express.static(__dirname + "/public"));在公共目录中启用静态内容,我们还通过以下行来设置所有请求的body解析器:app.use(bodyParser.json());

接下来,我们添加所有API操作,最后,我们设置应用程序的监听端口:app.listen(3000);

正如我们所看到的,在这个文件中,我们使用ExpressJS框架来定义API操作,目前我们有以下URL:

动词 URL 描述
GET api/contact 检索所有联系人
GET api/contact/id 按id检索联系人
POST api/contact 创建一个新联系人
PUT api/contact 更新现有联系人
删除 api/contact 删除现有联系人

所有这些URL都用于API,在server.js内部,我们有访问MongoDB数据库的实例,名为“contacts”的“表”必须具有以下列:

  • firstName
  • middleName
  • lastName
  • phone
  • email

我们可以根据需要设置API操作的约定。就我而言,我更喜欢使用api前缀,并使用单数名称来表示API中的实体或功能。

关于AngularJS,我们继续创建以下目录:

  • controllers:控制器存放位置
  • services:服务存放位置(控制器可重用对象)
  • views:HTML文件存放位置

现在,我们在根目录中添加一个名为app.js的文件来定义AngularJS模块。

var module = angular.module("contactManager", [
    "ngRoute",
    "ngAnimate",
    "toaster"
]);

(function (app) {
    app.config(function ($routeProvider) {
        var base = "/views/";

        $routeProvider
            .when("/", {
                templateUrl: base + "contact/index.html",
                controller: "HomeController",
                controllerAs: "vm"
            })
            .when("/contact/add", {
                templateUrl: base + "contact/add.html",
                controller: "ContactAddController",
                controllerAs: "vm"
            })
            .when("/contact/details/:id", {
                templateUrl: base + "contact/details.html",
                controller: "ContactDetailsController",
                controllerAs: "vm"
            })
            .when("/contact/edit/:id", {
                templateUrl: base + "contact/edit.html",
                controller: "ContactEditController",
                controllerAs: "vm"
            })
            .when("/contact/remove/:id", {
                templateUrl: base + "contact/remove.html",
                controller: "ContactRemoveController",
                controllerAs: "vm"
            });
    });
})(angular.module("contactManager"));

此文件包含AngularJS模块和路由表的定义,我们对路由表使用相同的命名约定,对实体使用单数。

services目录中,我们将放置模块的所有可注入服务。在此情况下,在此服务中,我们将添加提供所有API相关操作的代码。

(function (app) {
    "use strict";

    app.service("RepositoryService", RepositoryService);

    RepositoryService.$inject = ["$log", "$http"];

    function RepositoryService($log, $http) {
        var svc = this;

        var apiUrl = "/api";

        svc.getContacts = getContacts;
        svc.getContact = getContact;
        svc.createContact = createContact;
        svc.updateContact = updateContact;
        svc.deleteContact = deleteContact;

        function getContacts(fields) {
            var queryString = [];

            if (fields.pageSize) {
                queryString.push("pageSize=" + fields.pageSize);
            }

            if (fields.firstName) {
                queryString.push("firstName=" + fields.firstName);
            }

            if (fields.middleName) {
                queryString.push("middleName=" + fields.middleName);
            }

            if (fields.lastName) {
                queryString.push("lastName=" + fields.lastName);
            }

            var url = [apiUrl, "contact"].join("/");

            var fullUrl = queryString.length == 0 ? 
                          url : [url, "?", queryString.join("&")].join("");

            return $http.get(fullUrl);
        };

        function getContact(id) {
            return $http.get([apiUrl, "contact", id].join("/"));
        };

        function createContact(model) {
            return $http.post([apiUrl, "contact"].join("/"), model);
        };

        function updateContact(id, model) {
            return $http.put([apiUrl, "contact", id].join("/"), model);
        };

        function deleteContact(id) {
            return $http.delete([apiUrl, "contact", id].join("/"));
        };
    };
})(angular.module("contactManager"));

这是一个好习惯,因为使用服务可以避免在所有控制器中注入$http服务。相反,我们将注入RepositoryService,因为将来如果我们更改API的URL,我们不必担心更改所有控制器,我们只需更改服务。

controllers目录中,我们将为联系人的每个操作创建一个控制器:

  • HomeController
  • ContactAddController
  • ContactDetailsController
  • ContactEditController
  • ContactRemoveController

Home

(function (app) {
    "use strict";

    app.controller("HomeController", HomeController);

    HomeController.$inject = ["$location", "toaster", "RepositoryService"];

    function HomeController($location, toaster, repository) {
        var vm = this;

        vm.contacts = [];
        vm.search = {};
        vm.add = add;
        vm.search = search;
        vm.details = details;
        vm.remove = remove;

        toaster.pop("wait", "Loading contacts...");

        repository.getContacts(vm.search).then(function (result) {
            vm.contacts = result.data;
        });

        vm.add = function () {
            $location.path("/contact/add/");
        };

        vm.search = function () {
            repository.getContacts(vm.search).then(function (result) {
                vm.contacts = result.data;
            });
        };
        
        vm.details = function (id) {
            $location.path("/contact/details/" + id);
        };

        vm.remove = function (id) {
            $location.path("/contact/remove/" + id);
        };
    };
})(angular.module("contactManager"));

index.html代码文件

<h2>Contacts</h2>

<p>
    <a ng-click="vm.add()">Add new</a>
</p>

<div class="container">
    <div class="row">
        <div class="form-inline">
            <div class="form-group">
                <input type="text" name="firstName" class="form-control" 
                 placeholder="First name" ng-model="vm.search.firstName" />
            </div>

            <div class="form-group">
                <input type="text" name="middleName" class="form-control" 
                 placeholder="Middle name" ng-model="vm.search.middleName" />
            </div>

            <div class="form-group">
                <input type="text" name="lastName" class="form-control" 
                 placeholder="Last name" ng-model="vm.search.lastName" />
            </div>

            <div class="form-group">
                <select name="pageSize" class="form-control list-box" 
                 ng-model="vm.search.pageSize">
                    <option value="10" selected="selected">10</option>
                    <option value="25">25</option>
                    <option value="50">50</option>
                    <option value="100">100</option>
                </select>
            </div>

            <div class="form-group">
                <button type="button" 
                 class="btn btn-primary glyphicon glyphicon-search" 
                 ng-click="vm.search();" />
            </div>
        </div>
    </div>
</div>

<br />

<table class="table table-hover">
    <tr>
        <th>First name</th>
        <th>Middle name</th>
        <th>Last name</th>
        <th>Phone</th>
        <th>Email</th>
        <th></th>
    </tr>
    <tr ng-repeat="contact in vm.contacts">
        <td>{{ contact.firstName }}</td>
        <td>{{ contact.middleName }}</td>
        <td>{{ contact.lastName }}</td>
        <td>{{ contact.phone }}</td>
        <td>{{ contact.email }}</td>
        <td>
            <div class="dropdown">
                <button class="btn btn-primary btn-lg dropdown-toggle" 
                        type="button" data-toggle="dropdown">
                <span class="caret"></span></button>
                <ul class="dropdown-menu">
                    <li><a ng-click="vm.details(contact._id)">Details</a></li>
                    <li><a ng-click="vm.remove(contact._id)">Remove</a></li>
                </ul>
            </div>
        </td>
    </tr>
</table>

我们定义了控制器并注入了所有必需的服务:$locationRepositoryService,第一个服务用于重定向,第二个服务是API存储库。

请注意,我们没有使用$scope服务,而是使用了控制器的别名:vm,事实上,在所有HTML文件中,我们都将始终使用vm别名来访问控制器的成员。

添加联系人

(function (app) {
    "use strict";

    app.controller("ContactAddController", ContactAddController);

    ContactAddController.$inject = ["$location", "toaster", "RepositoryService"];

    function ContactAddController($location, toaster, repository) {
        var vm = this;

        vm.model = {};

        vm.save = save;
        vm.cancel = cancel;

        function save() {
            toaster.pop("wait", "Saving...");

            repository.createContact(vm.model).then(function (result) {
                toaster.pop("success", "The contact was saved successfully");

                $location.path("/");
            });
        };

        function cancel() {
            $location.path("/");
        };
    };
})(angular.module("contactManager"));

add.html代码文件

<h2>Create</h2>

<form name="form" novalidate ng-submit="vm.save()">
    <div class="form-horizontal">
        <h4>Contact</h4>
        <hr />

        <div class="form-group" ng-class="{ 'has-error': form.firstName.$invalid }">
            <label for="firstName" class="control-label col-md-2">First name</label>
            <div class="col-md-10">
                <input type="text" name="firstName" class="form-control" 
                 required ng-model="vm.model.firstName" />
                <span class="text-danger help-block" 
                 ng-show="form.firstName.$error.required">(*) Required</span>
            </div>
        </div>

        <div class="form-group">
            <label for="middleName" class="control-label col-md-2">Middle name</label>
            <div class="col-md-10">
                <input type="text" name="middleName" class="form-control" 
                 ng-model="vm.model.middleName" />
            </div>
        </div>

        <div class="form-group" ng-class="{ 'has-error': form.lastName.$invalid }">
            <label for="lastName" class="control-label col-md-2">Last name</label>
            <div class="col-md-10">
                <input type="text" name="lastName" class="form-control" 
                 required ng-model="vm.model.lastName" />
                <span class="text-danger help-block" 
                 ng-show="form.lastName.$error.required">(*) Required</span>
            </div>
        </div>

        <div class="form-group" ng-class="{ 'has-error': form.phone.$invalid }">
            <label for="phone" class="control-label col-md-2">Phone</label>
            <div class="col-md-10">
                <input type="text" name="phone" class="form-control" 
                 required ng-model="vm.model.phone" />
                <span class="text-danger help-block" 
                 ng-show="form.phone.$error.required">(*) Required</span>
            </div>
        </div>

        <div class="form-group" ng-class="{ 'has-error': form.email.$invalid }">
            <label for="email" class="control-label col-md-2">Email</label>
            <div class="col-md-10">
                <input type="text" name="email" class="form-control" 
                 required ng-model="vm.model.email" />
                <span class="text-danger help-block" 
                 ng-show="form.email.$error.required">(*) Required</span>
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" ng-disabled="!form.$valid" 
                 class="btn btn-primary" />
                <a ng-click="vm.cancel()">Cancel</a>
            </div>
        </div>
    </div>
</form>

联系人详细信息

(function (app) {
    "use strict";

    app.controller("ContactDetailsController", ContactDetailsController);

    ContactDetailsController.$inject = 
    ["$routeParams", "$location", "RepositoryService"];

    function ContactDetailsController($routeParams, $location, repository) {
        var vm = this;

        var id = $routeParams.id;

        vm.model = {};
        vm.edit = edit;
        vm.cancel = cancel;

        repository.getContact(id).then(function (result) {
            vm.model = result.data;
        });

        function edit() {
            $location.path("/contact/edit/" + id);
        };

        function cancel() {
            $location.path("/");
        };
    };
})(angular.module("contactManager"));

details.html代码文件

<h2>Details</h2>

<div>
    <h4>Contact</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>First name</dt>
        <dd>{{ vm.model.firstName }}</dd>

        <dt>Middle name</dt>
        <dd>{{ vm.model.middleName }}</dd>

        <dt>Last name</dt>
        <dd>{{ vm.model.lastName }}</dd>

        <dt>Phone</dt>
        <dd>{{ vm.model.phone }}</dd>

        <dt>Email</dt>
        <dd>{{ vm.model.email }}</dd>
    </dl>
</div>

<p>
    <a ng-click="vm.edit()">Edit</a> | <a ng-click="vm.cancel()">Cancel</a>
</p>

编辑联系人

(function (app) {
    "use strict";

    app.controller("ContactEditController", ContactEditController);

    ContactEditController.$inject = 
           ["$routeParams", "$location", "toaster", "RepositoryService"];

    function ContactEditController($routeParams, $location, toaster, repository) {
        var vm = this;

        var id = $routeParams.id;

        vm.model = {};
        vm.save = save;
        vm.cancel = cancel;

        repository.getContact(id).then(function (result) {
            vm.model = result.data;
        });

        function save() {
            toaster.pop("wait", "Saving...");

            repository.updateContact(id, vm.model).then(function (result) {
                toaster.pop("success", "The changes were saved successfully");

                $location.path("/contact/details/" + id);
            });
        };

        function cancel() {
            $location.path("/contact/details/" + id);
        };
    };
})(angular.module("contactManager"));

edit.html代码文件

<h2>Edit</h2>

<form name="form" novalidate ng-submit="vm.save()">
    <div class="form-horizontal">
        <h4>Contact</h4>
        <hr />

        <div class="form-group" ng-class="{ 'has-error': form.firstName.$invalid }">
            <label for="firstName" class="control-label col-md-2">First name</label>
            <div class="col-md-10">
                <input type="text" name="firstName" 
                 class="form-control" required ng-model="vm.model.firstName" />
                <span class="text-danger help-block" 
                 ng-show="form.firstName.$error.required">(*) Required</span>
            </div>
        </div>

        <div class="form-group">
            <label for="middleName" class="control-label col-md-2">Middle name</label>
            <div class="col-md-10">
                <input type="text" name="middleName" 
                 class="form-control" ng-model="vm.model.middleName" />
            </div>
        </div>

        <div class="form-group" ng-class="{ 'has-error': form.lastName.$invalid }">
            <label for="lastName" class="control-label col-md-2">Last name</label>
            <div class="col-md-10">
                <input type="text" name="lastName" 
                 class="form-control" required ng-model="vm.model.lastName" />
                <span class="text-danger help-block" 
                 ng-show="form.lastName.$error.required">(*) Required</span>
            </div>
        </div>

        <div class="form-group" ng-class="{ 'has-error': form.phone.$invalid }">
            <label for="phone" class="control-label col-md-2">Phone</label>
            <div class="col-md-10">
                <input type="text" name="phone" 
                 class="form-control" required ng-model="vm.model.phone" />
                <span class="text-danger help-block" 
                 ng-show="form.phone.$error.required">(*) Required</span>
            </div>
        </div>

        <div class="form-group" ng-class="{ 'has-error': form.email.$invalid }">
            <label for="email" class="control-label col-md-2">Email</label>
            <div class="col-md-10">
                <input type="text" name="email" class="form-control" 
                 required ng-model="vm.model.email" />
                <span class="text-danger help-block" 
                 ng-show="form.email.$error.required">(*) Required</span>
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" 
                 ng-disabled="!form.$valid" class="btn btn-primary" />
                <a ng-click="vm.cancel()">Cancel</a>
            </div>
        </div>
    </div>
</form>

删除联系人

(function (app) {
    "use strict";

    app.controller("ContactRemoveController", ContactRemoveController);

    ContactRemoveController.$inject = 
           ["$location", "$routeParams", "toaster", "RepositoryService"];

    function ContactRemoveController($location, $routeParams, toaster, repository) {
        var vm = this;

        var id = $routeParams.id;

        vm.model = {};
        vm.remove = remove;
        vm.cancel = cancel;

        repository.getContact(id).then(function (result) {
            vm.model = result.data;
        });

        function remove() {
            toaster.pop("wait", "Removing...");

            repository.deleteContact(id).then(function (result) {
                toaster.pop("success", "The contact was removed successfully");

                $location.path("/");
            });
        };

        function cancel() {
            $location.path("/");
        };
    };
})(angular.module("contactManager"));

remove.html代码文件

<h2>Remove</h2>

<h3>Are you sure to want remove this record?</h3>

<div>
    <h4>Contact</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>First name</dt>
        <dd>{{ vm.model.firstName }}</dd>

        <dt>Middle name</dt>
        <dd>{{ vm.model.middleName }}</dd>

        <dt>Last name</dt>
        <dd>{{ vm.model.lastName }}</dd>

        <dt>Phone</dt>
        <dd>{{ vm.model.phone }}</dd>

        <dt>Email</dt>
        <dd>{{ vm.model.email }}</dd>
    </dl>

    <div class="form-actions no-color">
        <a ng-click="vm.remove(vm.model._id)" class="btn btn-default">Delete</a>
        <a ng-click="vm.cancel()" class="btn btn-small">Cancel</a>
    </div>
</div>

最后,我们将拥有以下结构:

File Structure

现在,在命令行中,执行此命令:node server.js,然后打开浏览器并加载URL:https://:3000/,尝试在应用程序中添加、编辑和删除联系人,所有ID都由MongoDB引擎生成,因此我们无需担心ID。

步骤03 - 添加联系人模拟器

contact.mocker.js代码文件

var mongojs = require("mongojs");
var db = mongojs("contactManager", ["contacts"]);

var limit = 1000;

var firstNames = ["James", "John", "Robert", "Michael", "William", 
                  "David", "Richard", "Charles", "Joseph", "Thomas"];

var middleNames = ["Peter", "Lee", "Alexander", "Daniel", "Edward"];

var lastNames = ["Smith", "Johnson", "Williams", "Jones", "Brown", 
                 "Davis", "Miller", "Wilson", "Moore"];

var getRandomValue = function (min, max) {
    return Math.floor(Math.random() * ((max - min) + 1)) + min;
};

var getRandomItem = function (array) {
    return array[Math.floor(Math.random() * array.length)];
};

var phoneMocker = function () {
    var areaCode = getRandomValue(250, 500);
    var phoneNumber = getRandomValue(2000000, 5000000);

    return [areaCode, " ", phoneNumber].join("");
};

var emailMocker = function (contact) {
    var separators = ["", ".", "_", "", ".", "_"];
    var separator = getRandomItem(separators);

    var contactInfo = [contact.firstName, separator, 
                       contact.middleName, separator, contact.lastName].join("");

    var domains = ["outlook.com", "gmail.com", "yahoo.com"];

    return contactInfo.toLowerCase() + "@" + getRandomItem(domains);
};

for (var i = 0; i < limit; i++) {
    var firstName = getRandomItem(firstNames);
    var middleName = getRandomItem(middleNames);
    var lastName = getRandomItem(lastNames);

    var item = {
        firstName: firstName,
        middleName: middleName,
        lastName: lastName,
        phone: phoneMocker()
    };

    item.email = emailMocker(item);

    console.log("Inserting new row...");

    db.contacts.insert(item, function (err, doc) {
        if (err) {
            console.log(err);
        }
    });
}

要生成集合中的数据,我们可以从命令行运行contact.mocker.js文件:node contact.mocker.js。我们还可以设置记录的数量,在此示例中,限制为1000;名字、中间名和姓氏来自统计数据。

工作原理?它通过一个for循环来创建所有联系人,对于每个联系人,它从数组中以随机方式获取名字、中间名和姓氏,电话号码在一定范围内,电子邮件根据名字和随机分隔符生成。

代码改进

  • 为字段添加最大长度和正则表达式验证
  • 为AngularJS控制器添加单元测试
  • 添加身份验证

关注点

  • JavaScript是一种非类型化语言,但我们想用强类型语言开发,我们可以使用TypeScript,TypeScript是JavaScript的超集。
  • 对于JavaScript,我们使用严格模式,根据最佳实践,这使得编写“安全”的JavaScript更容易。
  • 如果我们需要访问另一种类型的数据库,我们可以安装所需的包并更改访问数据库的逻辑。

相关链接

历史

  • 2017年2月5日:初始版本
  • 2017年2月6日:添加了环境设置说明
  • 2017年2月22日:添加了联系人模拟器
  • 2017年10月3日:函数定义更改
© . All rights reserved.