实现一个完整的Node.js RESTful API的示例
文章标题:Node.js RESTful API实战——长沙网络推广的视角
前言:
今天,我将通过长沙网络推广的视角,分享一个关于如何使用Node.js构建完整的RESTful API的示例。这本书给了我很多启示,现在我想把这些宝贵的经验分享给你们。跟随我,一起走进Node.js的世界,感受用其编写接口的魅力。
一、环境搭建
你需要下载并安装Node.js。接着,安装npm包管理器。然后,你可以通过git克隆演示项目。进入项目文件夹后,运行相关命令下载项目所需的插件并启动项目。之后,你就可以通过访问接口文档来这个API了。
二、程序入口
Express这个框架功能丰富,应用广泛。在这个项目中,我们首先通过Express创建一个app实例。接着,我们使用consign模块来组织我们的代码。consign允许我们按照特定的顺序导入其他模块,这让代码看起来非常优雅。在这个项目中,模型的加载、路由的配置、中间件的引入等等,都是按照一定的顺序进行的。这样的设计使得项目结构清晰,易于维护。
三、模型设计
在我看来,需求分析是任何项目开始前的首要任务。经过需求分析后,我们会形成一个关于代码设计的总体概念。编码的本质是数据的存储和传递,同时还需要考虑性能和安全的问题。接下来,我们的任务就是设计数据模型,以反映需求分析的成果。在这个项目中,我们将通过Node.js和Express来构建数据模型,实现数据的增删改查等操作。我们还需要考虑如何设计API的接口,以便前端能够顺利地调用这些操作。在这个过程中,我们还需要注意代码的可读性和可维护性,以便在后续的开发和调试中能够更加方便。
这个项目是一个很好的实践Node.js和RESTful API的机会。通过实践,我们可以更好地理解Node.js的特性和优势,掌握构建RESTful API的方法和技巧。我们还可以学习到如何设计数据模型、如何组织代码结构、如何处理错误和异常等等。希望这篇文章能够给你带来一些启示和帮助,让你在Node.js的开发道路上更加顺利。在这个项目中,我们构建了两个核心模型:User和Task。每一个Task都对应一个User,而一个User可以同时拥有多个Task。这种关系体现了典型的任务分配模式,即每个用户都有各自的任务列表。
用户模型(User)
我们使用Sequelize作为ORM工具来定义数据库模型。Sequelize是一个基于Promise的Node.js ORM,它支持对PostgreSQL, MySQL, MariaDB, SQLite和Microsoft SQL Server等数据库的操作。在User模型中,我们定义了如下字段:
`id`:作为主键的自增整数,用于唯一标识每个用户。
`name`:用户的姓名,不允许为空。
`password`:用户的密码,同样不允许为空。在创建用户时,我们会使用bcrypt库来同步生成密码的哈希值,保证密码的安全性。
`email`:用户的地址,唯一且不允许为空。
我们还定义了一些关联和辅助方法,如`isPassword`用于验证密码是否正确,以及`associate`用于建立User和Task之间的多对多关系。
任务模型(Task)
在Task模型中,我们定义了如下字段:
`id`:作为主键的自增整数,用于唯一标识每个任务。
`title`:任务的标题,不允许为空。
`done`:一个布尔值,表示任务是否已完成,默认值为false。
同样,我们通过`associate`方法建立了Task与User之间的关联,表示每个Task都属于某个特定的User。
这个项目使用SQLite作为数据库存储系统,但不限于此,你可以根据项目的需求选择其他的关系型或非关系型数据库。Sequelize提供了对各种数据库的支持,使得数据的管理变得简单而灵活。除了Sequelize,还有很多其他的ORM工具如Mongoose(针对MongoDB)等,它们的核心思想都是基于数据模型的管理和验证。
在实际操作中,我们可能会对某些字段进行额外的验证,以确保数据的完整性和准确性。我们也会处理来自数据库的各种错误,以确保程序的稳定性和数据的可靠性。通过这两个模型,我们可以轻松地在Node.js环境中进行数据的增删改查操作,实现各种复杂的业务逻辑。在编程的世界里,关联属性就如同现实生活中的纽带,它们将不同的实体紧密地连接在一起。使用 Sequelize 这个强大的 Node.js ORM 工具,我们可以轻松地在数据库模型之间建立这些关联。现在让我们深入了解一下这段代码。
我们看到了两个关键的关联属性 `hasMany` 和 `belongsTo`。这两个属性在 Sequelize 中扮演着重要的角色,它们分别表示一对多和多对一的关系。简单地说,`hasMany` 表示一个用户拥有多个任务,而 `belongsTo` 则表示任务属于某个用户。这种明确的关联关系使得我们在进行数据库操作时,可以更加直观地理解和操作数据。
然后我们看到 `Users.isPassword` 这个类方法,它利用 bcrypt 模块对密码进行加密同步检查。这意味着,当我们需要验证用户的密码时,可以使用这个方法来进行密码的匹配。bcrypt 是一种强大的加密工具,它可以帮助我们保护用户的密码安全,防止被破解。
然后我们通过 `associate` 方法将这些模型连接起来。这个方法允许我们定义模型之间的关联关系,比如用户和任务之间的关联。通过这种方式,我们可以轻松地获取一个用户所有的任务,或者查找属于某个用户的任务。这种关联关系的建立为我们提供了极大的便利,使得我们可以更加高效地进行数据库操作。
这段代码为我们提供了一个强大的数据库管理框架。通过 Sequelize 和 bcrypt 的结合使用,我们可以轻松地进行数据库操作,同时保证数据的安全性。这个框架为我们提供了丰富的功能,使得我们可以根据需求进行各种复杂的数据库操作。无论是创建、读取、更新还是删除数据,都可以在这个框架下轻松完成。在代码中的CRUD操作时,我们首先要深入理解其背后的核心逻辑和框架设计。在router中,我们先从tasks.js的代码入手。这个模块主要处理关于任务(Tasks)的操作,包括获取任务列表、创建新任务、获取单个任务详情、更新任务和删除任务等。每一个操作都对应着CRUD中的一个动作:创建(Create)、读取(Read)、更新(Update)和删除(Delete)。这些操作通过路由的不同HTTP方法(如GET、POST、PUT和DELETE)进行触发,确保了数据的有效性和安全性。通过对这些操作的封装,我们能够在处理复杂的业务逻辑时,保证代码的简洁性和可读性。这些操作都经过了身份验证(authenticate),确保了只有经过授权的用户才能进行操作。在异常处理方面,代码采用了捕获异常的方式,当发生错误时,会返回相应的错误消息和状态码。接下来我们再看users.js的代码部分。这部分代码主要处理用户的操作,包括获取用户信息、删除用户、创建新用户等。这些操作同样遵循CRUD的原则,并且也经过了身份验证。在异常处理方面,代码同样采用了捕获异常的方式,确保了在发生错误时能够返回相应的错误信息。整体来看,这些路由设计简洁明了,遵循了CRUD的基本原则,并且通过异常处理机制确保了程序的稳定性和健壮性。通过这些代码,我们可以清晰地看到开发者是如何通过CRUD操作来管理用户数据的。这种设计方式不仅方便了开发者进行模块化的开发,也使得代码更加易于理解和维护。这些路由代码体现了良好的编程实践,包括模块化设计、CRUD操作以及异常处理等关键要素。通过这些代码,我们可以深入理解如何在Node.js环境下进行后端开发,并领略到代码背后所蕴含的设计思想和编程技巧。授权机制:JWT的应用与
在网络应用中,传递用户名和密码的方式已经显得过于简单直白,因此我们需要一种更为安全的授权机制。为此,该项目采用了基于JWT的授权方式。对于这一技术,可能有些读者还不是很熟悉,那么让我们一同这个授权机制的核心内容。
JWT授权的核心:生成与验证Token
授权机制主要分为两大步骤:生成Token和验证Token。而在这其中,最核心的部分就是如何生成token。
在项目中,当我们从前端接收到用户的和密码时,我们如何利用这些信息进行token的生成呢?答案是使用jwt-simple模块。这是一个简单的JWT生成和验证的Node.js库。通过它,我们可以轻松生成token。以下是关于如何生成token的代码片段:
```javascript
import jwt from "jwt-simple"; //引入jwt-simple模块
// 在接收到用户和密码后,进行以下操作
app.post("/token", (req, res) => {
const email = req.body.email; //从请求体中获取信息
const password = req.body.password; //从请求体中获取密码信息
if (email && password) { //确保和密码都存在
Users.findOne({where: {email: email}}) //查询数据库,找到对应的用户信息
.then(user => { //如果找到了用户信息
if (Users.isPassword(user.password, password)) { //验证密码是否正确
const payload = {id: user.id}; //创建payload,包含用户ID信息
res.json({token: jwt.encode(payload, cfg.jwtSecret)}); //生成并返回token
} else { //如果密码错误,返回错误状态码
res.sendStatus(401);
}
})
.catch(error => res.sendStatus(401)); //如果在查询过程中发生错误,返回错误状态码
} else { //如果没有和密码,返回错误状态码
res.sendStatus(401);
}
});
```
当我们谈论身份验证和授权时,passport和passport-jwt这两个模块将发挥重要作用。想象一下你正在开发一个应用程序,无论它是面向iOS用户还是Node开发者,你都需要确保用户身份的真实性和安全性。在这个过程中,passport支持多种授权策略,而其中最灵活的一层就是我们所称的“策略”。
让我们深入了解这个策略如何配置和应用。在你的应用程序中,首先需要配置授权策略并进行初始化。这里是一个基于passport和passport-jwt模块的示例代码。通过该代码,你可以轻松实现JWT(JSON Web Token)的身份验证。
从“passport”和“passport-jwt”模块导入必要的功能。这些模块提供了强大的工具来管理和验证用户身份。接下来,创建一个新的策略对象,使用从配置文件中获取的JWT密钥和从请求中提取JWT的函数作为参数。这个策略需要与数据库中的用户模型进行交互,以验证传入的JWT是否有效。
当接收到一个带有JWT的请求时,策略会查找数据库中与JWT负载中的用户ID相匹配的用户。如果找到匹配的用户,它将返回一个包含用户ID和电子邮件的对象,否则返回false表示身份验证失败。如果在查找过程中发生错误,它会捕获该错误并返回null。整个过程都被封装在一个策略对象中,使得身份验证过程更加简洁和灵活。
为了在项目中使用这个策略,你需要进行初始化和身份验证。通过调用passport的initialize方法来初始化策略,然后使用authenticate方法来执行身份验证。在调用authenticate方法时,你需要指定要使用的策略名称(在这里是“jwt”)以及其他配置选项。这样,你的应用程序就能够利用passport和passport-jwt模块来轻松实现身份验证和授权功能了。
现在,每当有人尝试访问你的应用程序时,他们都需要进行身份验证。通过配置适当的策略,你可以确保只有经过身份验证的用户才能访问特定的资源或执行敏感操作。这增加了应用程序的安全性并保护了用户的隐私。通过合理利用passport和passport-jwt模块提供的强大功能,你可以构建一个安全、可靠且用户友好的应用程序。在构建授权验证接口时,我们只需按照以下步骤进行配置即可。启用中间件(middleware)对所有请求进行身份验证,以确保请求的有效性。一旦验证通过,我们就可以进一步处理请求内容。以下是一个简单的示例代码:
```javascript
app.all(app.auth.authenticate()) // 对所有请求进行身份验证
.get((req, res) => {
console.log(`请求体内容:${JSON.stringify(req.body)}`); // 输出请求体内容
Tasks.findAll({ where: { user_id: req.user.id } }) // 根据用户ID查询任务列表
.then(result => res.json(result)) // 返回查询结果
.catch(error => {
res.status(412).json({ msg: error.message }); // 发生错误时返回错误信息
});
});
```
接下来,我们谈谈配置部分。在Node.js中,我们可以利用中间件(middleware)来扩展和增强我们的应用程序功能。下面是一段配置示例代码,其中涉及多个中间件的配置和使用:
```javascript
import bodyParser from "body-parser"; // 请求体的中间件
import express from "express"; // 主要的Web框架中间件
import cors from "cors"; // 允许跨域请求的中间件
import man from "man"; // 用于日志记录的中间件
import logger from "./logger"; // 日志模块
import pression from "pression"; // 请求压缩中间件
import helmet from "helmet"; // 安全防护的中间件
module.exports = app => {
"use strict";
app.set("port", 3000); // 设置服务器端口号
app.set("json spaces", 4); // 设置JSON输出的格式间距为4个空格
console.log(`err ${JSON.stringify(app.auth)}`); // 输出身份验证模块信息(这里可能需要修正)
app.use(bodyParser.json()); // 使用body-parser中间件JSON请求体
app.use(app.authitialize()); // 初始化身份验证中间件(假设已经定义)
app.use(pression()); // 使用请求压缩中间件来提升性能
app.use(helmet()); // 使用helmet中间件增强应用安全性能
// 其他中间件的配置和使用...(省略部分代码)...
};
用户路由的测试之旅:基于jwt的身份验证与API文档
在一个使用Express框架构建的现代应用程序中,确保用户路由的正常运行至关重要。本文将带您了解如何通过测试来确保用户路由的稳定性和安全性,并深入了解如何使用jwt进行身份验证,以及如何通过ApiDoc生成接口文档。
在开始之前,我们需要几个重要的模块来帮助我们进行测试和验证。我们将使用supertest来模拟HTTP请求,使用chai来进行断言,以及使用mocha作为测试框架。通过安装和配置这些模块,我们可以轻松地对我们的应用程序进行测试。
为了进行用户路由的测试,我们需要模拟用户数据的创建、获取和删除操作。我们将使用jwt-simple库生成和验证jwt令牌,并使用应用程序的配置信息来确保测试的顺利进行。
在测试之前,我们需要清除数据库中的用户数据,并创建一个新的用户进行测试。通过使用beforeEach钩子函数,我们可以在每个测试之前执行这些操作,以确保测试的独立性和一致性。然后,我们可以使用supertest模拟HTTP请求,并通过chai断言来验证响应结果是否符合预期。
对于GET /user路由的测试,我们将验证返回的用户数据是否与我们创建的用户匹配。我们将发送一个带有有效jwt令牌的GET请求,并断言响应的body包含正确的用户名和电子邮件地址。
对于DELETE /user路由的测试,我们将验证是否成功删除了创建的用户。我们将发送一个带有有效jwt令牌的DELETE请求,并断言响应的状态码为204(无内容),表示用户已成功删除。我们将在控制台中打印任何可能的错误消息。
对于POST /users路由的测试,我们将创建一个新用户并验证其数据是否正确。我们将发送一个包含用户名、电子邮件和密码的POST请求,并断言响应的body包含正确的用户名和电子邮件地址。
除了测试之外,接口文档也是非常重要的环节。我们将使用ApiDoc.js来生成接口文档,以便于其他开发人员理解和使用我们的API。通过ApiDoc.js,我们可以轻松地生成清晰、易于理解的接口文档,包括路由、请求参数、响应示例等详细信息。这将大大提高开发效率和代码的可维护性。
获取用户任务列表
`GET /tasks`
所属分组: 任务(Tasks)
授权头部: 需要用户提供经过身份验证的授权令牌(Authorization Token)。
头部示例:
```json
{
"Authorization": "xyz.abc.123.hgf"
}
```
成功响应: 返回任务列表的数组。
任务ID(tasks.id): 任务的唯一标识符。
任务标题(tasks.title): 任务的标题或描述。
任务完成状态(tasks.done): 表示任务是否完成的布尔值。
最后更新时间(tasks.updated_at): 任务最后更新的日期和时间。
创建时间(tasks.created_at): 任务注册的日期和时间。
用户ID(tasks.user_id): 与任务相关的用户的唯一标识符。
响应示例(成功):
```json
HTTP/1.1 200 OK
[
{
"id": 1,
"title": "学习", // “Study” in English, translates to "Learn" in Chinese.
"done": false, // Represents whether the task is completed or not.
"updated_at": "2016-02-10T15:46:51.778Z", // When the task was last updated.
"created_at": "2016-02-10T15:46:51.778Z", // When the task was created.
"user_id": 1 // The ID of the user who created the task.
}
// ... (Other tasks in the list)
]
```
错误响应示例: 当请求不符合预期条件时返回错误。例如,当请求的格式不正确或缺少必要的参数时。返回状态码 `HTTP/1.1 412 Precondition Failed`。具体的错误信息将在响应体中详细说明。您可以根据实际情况提供更具体的错误信息和处理建议。
终于走到了这一步,即将开启项目的发布之旅。在最后的准备阶段,还有一些关键的步骤和操作需要完成。其中一项重要的任务是为API设置访问权限,以确保数据的安全性和稳定性。
在这一阶段,我们将引入一个强大的模块——CORS(跨源资源共享)。关于CORS的详细介绍和用法,网络上已经有很多优秀的文章可供大家学习。在这个项目中,我们需要在代码中进行如下设置:
app.use(cors({
origin: [" // 允许访问的域名列表
methods: ["GET", "POST", "PUT", "DELETE"], // 允许的HTTP请求方法
allowedHeaders: ["Content-Type", "Authorization"] // 允许携带的请求头信息
}));
通过设置CORS,我们可以控制哪些域名可以访问我们的API,从而提高系统的安全性。我们还可以打印请求日志来监控API的使用情况,这对于排查问题和优化性能非常重要。为此,我们引入了winston模块来记录日志。
在即将发布的演示网站中,这些设置将起到至关重要的作用。通过这个阶段的准备,我们可以确保API的安全性、稳定性和可用性。通过打印请求日志,我们可以更好地了解用户的使用情况,为未来的产品迭代和功能优化提供有力的数据支持。
在项目的深处,隐藏着一份对效能的专注与追求。我们对日志进行了精细化的配置与管理。通过引入winston模块,我们为应用程序创建了一个强大的日志系统。这个系统能够捕捉并记录每一次API请求的细节,从请求类型到响应状态码,再到具体的执行时间,一切都被精准地记录下来。以下是日志配置的精彩部分:
```javascript
import fs from "fs";
import winston from "winston";
if (!fs.existsSync("logs")) {
fs.mkdirSync("logs");
}
const logger = new winston.Logger({
transports: [
new winston.transports.File({
level: "info",
filename: "logs/app.log",
maxsize: 1048576, // 这里的数字代表文件大小限制,单位是字节。一旦超过这个大小,会自动创建新的日志文件。最大限制是创建新的日志文件数量限制为10个。这对于维护和管理大型日志文件非常有用。但注意这个设置会影响到日志文件的大小和数量。需要定期清理和维护日志文件以避免存储空间耗尽。这个设置非常重要,因为它可以让我们跟踪和调试应用程序中的问题。我们设置了一个颜色选项为false,因为我们在控制台输出日志时不需要颜色编码。颜色编码主要用于可视化工具或命令行终端中的信息高亮显示,这在处理大量的文本输出时可能会干扰阅读和理解。通过设置它为false,我们可以避免这种干扰,使得日志输出更加清晰明了。并且保证了在各种环境中输出的格式统一。这种处理方式使得我们的日志系统更加灵活和可靠,同时也保证了系统的稳定性。并且它提供了一个统一的接口来管理和处理所有的日志信息。这对于开发和运维人员来说是非常有用的工具。通过它我们可以轻松地跟踪和调试应用程序中的问题。对于开发人员来说,它可以帮助我们更好地理解应用程序的运行状态和行为,对于运维人员来说,它可以帮助他们快速定位和解决问题。这对于任何应用程序来说都是非常重要的工具之一。所以我们选择了这个强大的日志系统作为我们的基础架构的一部分。"info","message":"message description"} 这个属性是必要的因为它告诉我们当前的日志级别是什么。通过调用这个方法我们可以创建一个新的日志文件并将其添加到我们的日志系统中以便于后续的查看和管理。"message"属性则是我们想要记录的具体的消息内容它可以包含任何我们想要记录的信息比如用户请求的信息、系统状态的变化等等这些信息对于后续的调试和问题排查非常有帮助。"timestamp"属性则记录了这条日志信息的产生时间这对于我们后续查看和分析日志信息的时间顺序非常有帮助。"message description"是具体的消息描述它可以让我们更好地理解和分析这条日志信息背后的含义和问题所在通过这个日志系统我们可以轻松地进行问题排查和调试使得我们的应用程序更加稳定和可靠。"timestamp":"timestamp description"} 这样我们就可以在控制台中看到详细的日志信息了包括请求的IP地址、请求的类型(GET或POST等)、请求的URL以及响应的状态码等这些信息对于了解应用程序的运行状态和问题排查非常有帮助。"timestamp description"是具体的日期和时间描述它可以帮助我们准确地定位这条日志信息是在何时产生的这对于我们分析问题的发生时间和持续时间非常有帮助。这些配置都是为了更好地管理我们的应用程序确保它能够稳定运行并为我们提供准确的数据和信息。"message description"是具体的消息描述它包含了关于这条日志信息的详细内容这些信息可能是关于某个操作的执行结果也可能是关于某个错误的详细信息等等这些信息对于理解应用程序的运行状态和解决问题非常有帮助。"timestamp description"则是时间戳描述它可以帮助我们了解这条日志信息是在何时产生的这对于跟踪和分析问题的发生和解决过程非常有帮助。",因此我们将创建一个强大的日志系统来帮助我们更好地管理和维护我们的应用程序确保它能够稳定运行并提供准确的数据和信息给开发人员和运维人员使用。接下来我们将详细介绍前端程序部分。为了更好地展示API的功能我将前端代码也上传到了仓库可以直接下载后运行查看API的具体表现。"你的程序构建工作已完成我们可以进一步处理数据了。"这就是整个项目的日志系统部分以及前端程序的介绍整个项目的目标是构建一个稳定、可靠且易于管理的应用程序使得开发者能够轻松地开发和调试应用程序同时也让用户能够体验到高效的应用程序功能享受高效、稳定的服务。"您的项目正在进行中我们将继续完善和改进我们的代码以确保其质量和性能。"接下来我们将介绍其他部分的代码包括使用Node.js的cluster模块利用机器的多核性能进行优化使用gzip压缩模块进行数据压缩以支持https的访问使用helmet模块进行安全防护等等这些配置都是为了提升程序的性能和安全性使得它能够更好地服务于用户满足用户的需求并为企业带来更大的商业价值。"让我们开始吧我们将一步步构建高效、可靠的应用程序让用户享受到更好的服务体验。"现在让我们深入了解代码的细节吧!我们将逐步每一行代码以便更好地理解整个程序的运行过程和功能实现。"现在让我们一步步深入了解这个程序吧!"我们需要分析每个模块的功能以及它们如何协同工作以创建一个高效且强大的应用程序。这是一个挑战性的任务但也是一个令人兴奋的机会让我们深入了解代码的细节吧!"让我们一起这个程序的奥秘吧!"在这个过程中我们将深入理解每个模块的细节以及它们如何相互协作以创建出一个高效、稳定的应用程序同时也将了解如何处理可能出现的错误和问题以确保程序的正常运行和用户的满意程度。"你的努力将得到回报你的应用程序将会让用户满意。"你的程序已经准备好迎接用户的挑战了!在这个过程中你需要注意代码的质量和结构确保它们是易于维护和扩展的同时也要驾驭代码的桥梁——API的连接艺术
这本书犹如一把钥匙,为我打开了一个全新的世界。虽然内容并不复杂,但它涵盖了API连接的基础知识,让我得以自由并延伸我的知识边界。我对作者的编程才华深感钦佩,他驾驭代码的能力让我叹为观止。
API,作为连接不同代码段的关键桥梁,其重要性不言而喻。这本书深入浅出地介绍了API的连接技术,让我对API有了更深入的理解。通过学习和实践,我逐渐掌握了API的使用技巧,并在实践中不断尝试创新。
我深知自己的水平还有待提高。尽管我从这本书中学到了很多,但我仍然觉得自己在将所学转化为实践时有所欠缺。有时候,我无法准确地将理论知识应用于实际项目中。我在此恳请各位读者,如果我的表述或理解有误,请不吝指正。您的宝贵意见将是我前进的动力。
这本书不仅让我对API有了更深入的了解,还激发了我对编程的热情。我希望通过分享我的学习心得,能为大家提供一些帮助和启示。我也想借此机会向大家推荐狼蚁SEO,希望大家多多关注和支持。在这里,我们可以一起编程的奥秘,分享技术的心得,共同进步。
这本书不仅教会了我API的连接技术,还激发了我对编程的热情和求知欲。我相信,只要我们不断,不断学习,我们就能驾驭代码的世界,创造出无限可能。感谢这本书,让我有幸踏入了这个精彩的世界。期待更多读者能够加入我们,共同这个充满挑战和机遇的世界。
编程语言
- 实现一个完整的Node.js RESTful API的示例
- Bootstrap每天必学之导航条
- VUE JS 使用组件实现双向绑定的示例代码
- vue2手机APP项目添加开屏广告或者闪屏广告
- Vue 实现前端权限控制的示例代码
- 记录一次排查PHP脚本执行卡住的问题
- PHP类相关知识点实例总结
- Vue的computed(计算属性)使用实例之TodoList
- AngularJs bootstrap详解及示例代码
- Vue2.x中的父子组件相互通信的实现方法
- PHP注释语法规范与命名规范详解篇
- 一文让你彻底搞清楚javascript中的require、import与
- php实现分页显示
- jQuery判断网页是否已经滚动到浏览器底部的实现
- 基于javascript实现简单的抽奖系统
- vue将单页面改造成多页面应用的方法