(摘) Node.js光速入门再出门

声明:内容源自网络,版权归原作者所有。若有侵权请在网页聊天中联系我

Node.js官网 文档

现在才来看Node.js有点晚,到处都可以见到它的踪迹。不过快速的学习一下也没啥问题,不指它当主力。当前最新21.6.0。
Node.js 是能够在服务端运行JavaScript的开放源代码、跨平台执行环境。Node.js 在浏览器之外运行 V8 JavaScript 引擎,这是 Google Chrome 的核心。这使得 Node.js 的性能非常高。
简单来说,就是把javascript作为后端语言,脱离了它原来只在网页上干的那点事。
看起来,也可以通过一些工具来打包为可执行文件:https://github.com/nexe/nexe

HelloWorld

const http = require('node:http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});
server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

命令行运行 node helloworld.js 即呈现一个Web服务器。整个代码看起来还是很简单明了的。

npm

npm是Node.js的标准包管理器。

npm install 安装所有信赖项

npm install <包名> 安装单个软件包

npm update 更新包

使用淘宝镜像的命令:npm install -g cnpm –registry=https://registry.npmmirror.com
淘宝 NPM 镜像是一个完整 npmjs.org 镜像,这样就可以使用 cnpm 命令来安装模块了:cnpm install [name]

示例

以下示例异步显示文件相关信息

const fs = require('node:fs');
fs.stat('/Users/joe/test.txt', (err, stats) => {
  if (err) {
    console.error(err);
    return;
  }
  stats.isFile(); // true
  stats.isDirectory(); // false
  stats.isSymbolicLink(); // false
  stats.size; // 1024000 //= 1MB
});

或者使用promise方法,它同步等待返回

const fs = require('node:fs/promises');
async function example() {
  try {
    const stats = await fs.stat('/Users/joe/test.txt');
    stats.isFile(); // true
    stats.isDirectory(); // false
    stats.isSymbolicLink(); // false
    stats.size; // 1024000 //= 1MB
  } catch (err) {
    console.log(err);
  }
}
example();

看起来Node.js已经有非常多的库,足以解决很多问题。以下是一个Web服务器示例。

// 0. 导入模块
const http = require("http");
const url = require("url");
const fs = require("fs");

// 1. 创建服务
const server = http.createServer((req, res) => {
    // 1.1 解析 url
    const { query, pathname } = url.parse(req.url, true);

    if (pathname === "/a") {
        // 如果访问的是 /a 那么读取 client目录下的views目录下的pageA.html 并返回出去
        fs.readFile("./client/views/pageA.html", "utf-8", (err, data) => {
            if (err) return console.log(err);

            res.end(data);
        });
    }

    if (pathname === "/b") {
        res.end("hello pageB");
    }

    if (pathname === "/list") {
        // 如果访问的是 /list 那么读取 client目录下的views目录下的list.html 并返回出去
        fs.readFile("./client/views/list.html", "utf-8", (err, data) => {
            if (err) return console.log(err);

            res.end(data);
        });
    }
});

// 2. 给服务配置端口号
server.listen(8080, () => console.log("开启服务成功, 端口号为 8080"));

继续完善,解决css、js等静态文件

// 0. 导入模块
const http = require("http");
const url = require("url");
const fs = require("fs");
const path = require("path");

// 1. 创建服务
const server = http.createServer((req, res) => {
    const { query, pathname } = url.parse(req.url, true);

    /**
     *  约定
     *      如果请求的 地址 是以 /views 开头
     *      表明你需要访问的是 html 文件, 后续写上 html 文件名即可
     *      比如你要请求 home.html
     *          => 请求地址: /views/home.html
     */
    if (/^\/views/.test(pathname)) {
        // 代码来到这里, 表明我们需要的是一个 html 文件
        // console.log(pathname)

        const { base } = path.parse(pathname);
        fs.readFile(`./client/views/${base}`, "utf-8", (err, data) => {
            if (err) {
                fs.readFile("./client/views/404.html", "utf-8", (err, data) => {
                    if (err) return console.log(err);
                    res.end(data);
                });
                return;
            }

            res.end(data);
        });
    }

    /**
     *  约定
     *      如果请求的地址 是以 /style 开头
     *      表明你需要访问的是 css 文件, 后续写上 css 文件名即可
     *      比如你要请求 list.css
     *          => 请求地址 /style/list.css
     */
    if (/^\/style/.test(pathname)) {
        // 代码来到这里, 表明我们需要的是一个 css 文件

        const { base } = path.parse(pathname);
        fs.readFile(`./client/css/${base}`, "utf-8", (err, data) => {
            if (err) {
                res.end("");
                return;
            }

            res.end(data);
        });
    }
});

// 2. 给服务配置端口号
server.listen(8080, () => console.log("开启服务成功, 端口号为 8080"));

接口和静态文件,与上相同的方法

// 0. 导入模块
const http = require("http");
const url = require("url");
const fs = require("fs");
const path = require("path");

// 1. 创建服务
const server = http.createServer((req, res) => {
    const { query, pathname } = url.parse(req.url, true);

    /**
     *  约定
     *      => 把 html/css/js/img/video/audio/icon 叫做 静态资源
     *      => 只要你请求的是 静态资源, 统一以 /static 开头
     *      => 只要你请求的是 接口数据, 统一以 /api 开头
     */

    // 1. 判断当前请求的是静态资源
    if (/^\/static/.test(pathname)) {
        // 1.1 解析 pathname
        const { base, ext } = path.parse(pathname);
        // 1.2 通过 后缀名 和 base, 确定读取文件的路径
        let filePath = "./client/";
        switch (ext) {
            case ".html":
                filePath += "views/";
                break;
            case ".css":
                filePath += "css/";
                break;
            case ".js":
                filePath += "js/";
                break;
        }
        // 1.3 拼接 base
        filePath += base; // ./client/views/list.html

        // 2. 读取文件
        fs.readFile(filePath, "utf-8", (err, data) => {
            if (err) {
                if (ext === ".html") {
                    // 返回 404 文件
                    fs.readFile("./404.html", "utf-8", (err, data) => {
                        if (err) return console.log(err);
                        res.end(data);
                    });
                } else {
                    res.end("");
                }
                return;
            }

            res.end(data);
        });
    }

    // 2. 判断当前请求的是 接口数据
    if (/^\/api/.test(pathname)) {
        if (pathname === "/api/goods/list" && req.method === "GET") {
            // 如果 当前请求的 地址 是 '/api/goods/list' 并且是 GET 请求

            // 去数据库读取数据, 返回给前端
            const info = {
                code: 1,
                message: "从数据库读取数据成功",
                list: [{}, {}, {}],
            };

            res.end(JSON.stringify(info));
        }
    }
});

// 2. 给服务配置端口号
server.listen(8080, () => console.log("开启服务成功, 端口号为 8080"));

完成请求参数

// 0. 导入模块
const http = require("http");
const url = require("url");
const fs = require("fs");
const path = require("path");

// 1. 创建服务
const server = http.createServer((req, res) => {
    /**
     *  假设: 你是一个 带有参数的 GET 请求
     *      http://localhost:8080/api/news/list?current=1&pagesize=12%date=20221127
     *      被 url.parse 方法解析
     *      pathname => /api/news/list
     *      query => { current: 1, pagesize: 12, date; 20221127 }
     */
    const { query, pathname } = url.parse(req.url, true);

    // 1. 判断当前请求的是静态资源
    if (/^\/static/.test(pathname)) {
        // 1.1 解析 pathname
        const { base, ext } = path.parse(pathname);
        // 1.2 通过 后缀名 和 base, 确定读取文件的路径
        let filePath = "./client/";
        switch (ext) {
            case ".html":
                filePath += "views/";
                break;
            case ".css":
                filePath += "css/";
                break;
            case ".js":
                filePath += "js/";
                break;
        }
        // 1.3 拼接 base
        filePath += base; // ./client/views/list.html

        // 2. 读取文件
        fs.readFile(filePath, "utf-8", (err, data) => {
            if (err) {
                if (ext === ".html") {
                    // 返回 404 文件
                    fs.readFile("./404.html", "utf-8", (err, data) => {
                        if (err) return console.log(err);
                        res.end(data);
                    });
                } else {
                    res.end("");
                }
                return;
            }

            res.end(data);
        });
    }

    // 2. 判断当前请求的是 接口数据
    if (/^\/api/.test(pathname)) {
        if (pathname === "/api/goods/list" && req.method === "GET") {
            // 如果 当前请求的 地址 是 '/api/goods/list' 并且是 GET 请求

            // 去数据库读取数据, 返回给前端
            const info = {
                code: 1,
                message: "从数据库读取数据成功",
                list: [{}, {}, {}],
            };

            res.end(JSON.stringify(info));
        }
        // 获取get请求的参数
        if (pathname === "/api/news/list" && req.method === "GET") {
            const info = { code: 1, message: "获取新闻列表成功" };
            if (!query.current) {
                info.code = 0;
                info.message = "没有 current 参数";
            } else if (!query.pagesize) {
                info.code = 0;
                info.message = "没有 pagesize 参数";
            } else if (!query.date) {
                info.code = 0;
                info.message = "没有 date 参数";
            } else {
                // 表示参数不缺
                info.list = [{}, {}, {}, {}];
                info.params = query;
            }
            res.end(JSON.stringify(info));
        }
        // 获取post请求的参数
        if (pathname === "/api/users/login" && req.method === "POST") {
            /**
             *  需要的参数有两个 username 和 password
             *      事件1: req.on('data', () => {})
             *              只要请求体内有信息, 就会开始接收, 并且是逐步接收
             *      事件2: req.on('end', () => {})
             *              当请求体内的参数接受完毕, 触发
             */
            let str = "";
            req.on("data", (chunk) => (str += chunk));

            req.on("end", () => {
                /**
                 *  世界规范:
                 *      要么传递查询字符串, 要么传递 json 字符串
                 *      我们只需要按照 查询字符串的格式, 或者 json 字符串的格式解析参数即可
                 *      要求就是前端在请求头中告诉我们按照什么格式解析字符串
                 *  世界规范:
                 *      在请求头中通过 content-type 告诉后端按照什么格式解析参数
                 *          如果 content-type 值为 application/x-www-form-urlencoded 那么按照 查询字符串解析
                 *          如果 content-type 值为 application/json 按照 json 字符串解析
                 */
                let params = null;
                if (req.headers["content-type"] === "application/json") {
                    // 按照 json 的格式转换
                    params = JSON.parse(str);
                }
                if (
                    req.headers["content-type"] ===
                    "application/x-www-form-urlencoded"
                ) {
                    // 按照 查询字符串 的格式转换
                    params = url.parse("?" + str, true).query;
                }
                const info = {
                    code: 1,
                    message: "请求成功",
                    params,
                };
                res.end(JSON.stringify(info));
            });
        }
    }
});

// 2. 给服务配置端口号
server.listen(8080, () => console.log("开启服务成功, 端口号为 8080"));

看起来还是得一个库来解决,否则写起来还是累。

回调、同步、异步

Node.js 异步编程的直接体现就是回调

阻塞代码(同步)

var fs = require("fs");

var data = fs.readFileSync('input.txt');

console.log(data.toString());
console.log("程序执行结束!");

非阻塞代码(异步)

var fs = require("fs");

fs.readFile('input.txt', function (err, data) {
    if (err) return console.error(err);
    console.log(data.toString());
});

console.log("程序执行结束!");

模块系统

var hello=require('./hello');    // 这里引入hello.js模块
hello.world(); // 调用world函数

在hello.js中

exports.world=function(){  // 使用exports将模块公开
    console.log("hello world");
}

把对象封装到模块:

//hello.js 
function Hello() { 
	var name; 
	this.setName = function(thyName) { 
		name = thyName; 
	}; 
	this.sayHello = function() { 
		console.log('Hello ' + name); 
	}; 
}; 
module.exports = Hello;

// main.js调用
var Hello = require('./hello'); 
hello = new Hello(); 
hello.setName('BYVoid'); 
hello.sayHello(); 

EventEmitter

EventEmitter 的核心就是事件触发与事件监听器功能的封装。

// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();

使用示例

//event.js 文件
var EventEmitter = require('events').EventEmitter; 
var event = new EventEmitter(); 
event.on('some_event', function() { 
	console.log('some_event 事件触发'); 
}); 
setTimeout(function() { 
	event.emit('some_event'); 
}, 1000); 

这里自定义了一个事件,我试图改为中文事件名也成功。

示例

var events = require('events'); 
var emitter = new events.EventEmitter(); 
emitter.on('someEvent', function(arg1, arg2) { 
	console.log('listener1', arg1, arg2); 
}); 
emitter.on('someEvent', function(arg1, arg2) { 
	console.log('listener2', arg1, arg2); 
}); 
emitter.emit('someEvent', 'arg1 参数', 'arg2 参数'); 

这里定义了两个相同的事件名,并且传递了参数。结果将按先来后到的顺序调用。

换一种方式,先定义函数,再挂上监听:

var events = require('events');
var eventEmitter = new events.EventEmitter();

// 监听器 #1
var listener1 = function listener1() {
   console.log('监听器 listener1 执行。');
}

// 监听器 #2
var listener2 = function listener2() {
  console.log('监听器 listener2 执行。');
}

// 绑定 connection 事件,处理函数为 listener1 
eventEmitter.addListener('connection', listener1);

// 绑定 connection 事件,处理函数为 listener2
eventEmitter.on('connection', listener2);

var eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + " 个监听器监听连接事件。");

// 处理 connection 事件 
eventEmitter.emit('connection');

// 移除监绑定的 listener1 函数
eventEmitter.removeListener('connection', listener1);
console.log("listener1 不再受监听。");

// 触发连接事件
eventEmitter.emit('connection');

eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + " 个监听器监听连接事件。");

console.log("程序执行完毕。");

打包可执行

安装: npm install -g nexe
打包:cat .\03-helloworld.js | nexe –build (从github.com没有对应的构建版本,需要通过–build来创建)
(构建失败,安装了所需的NASM,又需要VS,卒,VS太大了,又不绿色。)

GET/POST请求

// 获取GET请求内容

var http = require('http');
var url = require('url');
var util = require('util');
 
http.createServer(function(req, res){
    res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
    res.end(util.inspect(url.parse(req.url, true)));
}).listen(3000);


// 获取URL参数

var http = require('http');
var url = require('url');
var util = require('util');
 
http.createServer(function(req, res){
    res.writeHead(200, {'Content-Type': 'text/plain'});
 
    // 解析 url 参数
    var params = url.parse(req.url, true).query;
    res.write("网站名:" + params.name);
    res.write("\n");
    res.write("网站 URL:" + params.url);
    res.end();
 
}).listen(3000);


// 获取POST请求内容

var http = require('http');
var querystring = require('querystring');
var util = require('util');
 
http.createServer(function(req, res){
    // 定义了一个post变量,用于暂存请求体的信息
    var post = '';     
 
    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
    req.on('data', function(chunk){    
        post += chunk;
    });
 
    // 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
    req.on('end', function(){    
        post = querystring.parse(post);
        res.end(util.inspect(post));
    });
}).listen(3000);



var http = require('http');
var querystring = require('querystring');
 
var postHTML = 
  '<html><head><meta charset="utf-8"><title>菜鸟教程 Node.js 实例</title></head>' +
  '<body>' +
  '<form method="post">' +
  '网站名: <input name="name"><br>' +
  '网站 URL: <input name="url"><br>' +
  '<input type="submit">' +
  '</form>' +
  '</body></html>';
 
http.createServer(function (req, res) {
  var body = "";
  req.on('data', function (chunk) {
    body += chunk;
  });
  req.on('end', function () {
    // 解析参数
    body = querystring.parse(body);
    // 设置响应头部信息及编码
    res.writeHead(200, {'Content-Type': 'text/html; charset=utf8'});
 
    if(body.name && body.url) { // 输出提交的数据
        res.write("网站名:" + body.name);
        res.write("<br>");
        res.write("网站 URL:" + body.url);
    } else {  // 输出表单
        res.write(postHTML);
    }
    res.end();
  });
}).listen(3000);

OS 模块

var os = require("os");

// CPU 的字节序
console.log('endianness : ' + os.endianness());

// 操作系统名
console.log('type : ' + os.type());

// 操作系统名
console.log('platform : ' + os.platform());

// 系统内存总量
console.log('total memory : ' + os.totalmem() + " bytes.");

// 操作系统空闲内存量
console.log('free memory : ' + os.freemem() + " bytes.");

Express 框架

之前的Web服务器示例中,就是自己硬代码,有这个框架就可以吃“软”的。使用 Express 可以快速地搭建一个完整功能的网站。

cnpm install express


//express_demo.js 文件
var express = require('express');
var app = express();
 
app.get('/', function (req, res) {
   res.send('Hello World');
})
 
var server = app.listen(8081, function () {
 
  var host = server.address().address
  var port = server.address().port
 
  console.log("应用实例,访问地址为 http://%s:%s", host, port)
 
})

简洁多了,以下代码响应不同的方法及路由:


var express = require('express');
var app = express();
 
//  主页输出 "Hello World"
app.get('/', function (req, res) {
   console.log("主页 GET 请求");
   res.send('Hello GET');
})
 
 
//  POST 请求
app.post('/', function (req, res) {
   console.log("主页 POST 请求");
   res.send('Hello POST');
})
 
//  /del_user 页面响应
app.get('/del_user', function (req, res) {
   console.log("/del_user 响应 DELETE 请求");
   res.send('删除页面');
})
 
//  /list_user 页面 GET 请求
app.get('/list_user', function (req, res) {
   console.log("/list_user GET 请求");
   res.send('用户列表页面');
})
 
// 对页面 abcd, abxcd, ab123cd, 等响应 GET 请求
app.get('/ab*cd', function(req, res) {   
   console.log("/ab*cd GET 请求");
   res.send('正则匹配');
})
 
 
var server = app.listen(8081, function () {
 
  var host = server.address().address
  var port = server.address().port
 
  console.log("应用实例,访问地址为 http://%s:%s", host, port)
 
})

静态文件是必须的


var express = require('express');
var app = express();
 
app.use('/public', express.static('public'));   // 其实就是这一行
 
app.get('/', function (req, res) {
   res.send('Hello World');
})
 
var server = app.listen(8081, function () {
 
  var host = server.address().address
  var port = server.address().port
 
  console.log("应用实例,访问地址为 http://%s:%s", host, port)
 
})

GET方法

// index.html文件

<html>
<body>
<form action="http://127.0.0.1:8081/process_get" method="GET">
First Name: <input type="text" name="first_name">  <br>
 
Last Name: <input type="text" name="last_name">
<input type="submit" value="Submit">
</form>
</body>
</html>

// server.js

var express = require('express');
var app = express();
 
app.use('/public', express.static('public'));   // 静态文件处理
 
app.get('/index.html', function (req, res) {    
   res.sendFile( __dirname + "/" + "index.html" );  // 返回当前目录下的index.html文件内容
})
 
app.get('/process_get', function (req, res) { 
 
   // 输出 JSON 格式
   var response = {
       "first_name":req.query.first_name,   // 这里获取前端提交的变量
       "last_name":req.query.last_name
   };
   console.log(response);
   res.end(JSON.stringify(response));
})
 
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
 
console.log("应用实例,访问地址为 http://%s:%s", host, port)
 
})

POS方法

// index.html

<html>
<body>
<form action="http://127.0.0.1:8081/process_post" method="POST">
First Name: <input type="text" name="first_name">  <br>
 
Last Name: <input type="text" name="last_name">
<input type="submit" value="Submit">
</form>
</body>
</html>


// server.js

var express = require('express');
var app = express();
var bodyParser = require('body-parser');
 
// 创建 application/x-www-form-urlencoded 编码解析
var urlencodedParser = bodyParser.urlencoded({ extended: false })
 
app.use('/public', express.static('public'));
 
app.get('/index.html', function (req, res) {
   res.sendFile( __dirname + "/" + "index.html" );
})
 
app.post('/process_post', urlencodedParser, function (req, res) {
 
   // 输出 JSON 格式
   var response = {
       "first_name":req.body.first_name,
       "last_name":req.body.last_name
   };
   console.log(response);
   res.end(JSON.stringify(response));
})
 
var server = app.listen(8081, function () {
 
  var host = server.address().address
  var port = server.address().port
 
  console.log("应用实例,访问地址为 http://%s:%s", host, port)
 
})

GET从query中获取,POST从body中获取。

文件上传,这也是经常用到的

// index.html

<html>
<head>
<title>文件上传表单</title>
</head>
<body>
<h3>文件上传:</h3>
选择一个文件上传: <br />
<form action="/file_upload" method="post" enctype="multipart/form-data">
<input type="file" name="image" size="50" />
<br />
<input type="submit" value="上传文件" />
</form>
</body>
</html>


// server.js

var express = require('express');
var app = express();
var fs = require("fs");
 
var bodyParser = require('body-parser');
var multer  = require('multer');
 
app.use('/public', express.static('public'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(multer({ dest: '/tmp/'}).array('image'));
 
app.get('/index.html', function (req, res) {
   res.sendFile( __dirname + "/" + "index.html" );
})
 
app.post('/file_upload', function (req, res) {
 
   console.log(req.files[0]);  // 上传的文件信息
 
   var des_file = __dirname + "/" + req.files[0].originalname;
   fs.readFile( req.files[0].path, function (err, data) {
        fs.writeFile(des_file, data, function (err) {
         if( err ){
              console.log( err );
         }else{
               response = {
                   message:'File uploaded successfully', 
                   filename:req.files[0].originalname
              };
          }
          console.log( response );
          res.end( JSON.stringify( response ) );
       });
   });
})
 
var server = app.listen(8081, function () {
 
  var host = server.address().address
  var port = server.address().port
 
  console.log("应用实例,访问地址为 http://%s:%s", host, port)
 
})

Cookie

var express      = require('express')
var cookieParser = require('cookie-parser')
var util = require('util');
 
var app = express()
app.use(cookieParser())
 
app.get('/', function(req, res) {
    console.log("Cookies: " + util.inspect(req.cookies));  // 获取到了请求中的cookies
})
 
app.listen(8081)

连接MySQL

cnpm install mysql 安装

连接


var mysql      = require('mysql');
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'root',
  password : '123456',
  database : 'test'
});
 
connection.connect();
 
connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
  if (error) throw error;
  console.log('The solution is: ', results[0].solution);
});

增删改查


var mysql  = require('mysql');  
 
var connection = mysql.createConnection({     
  host     : 'localhost',       
  user     : 'root',              
  password : '123456',       
  port: '3306',                   
  database: 'test' 
}); 
 
connection.connect();
 
var  sql = 'SELECT * FROM websites';
//查
connection.query(sql,function (err, result) {
        if(err){
          console.log('[SELECT ERROR] - ',err.message);
          return;
        }
 
       console.log('--------------------------SELECT----------------------------');
       console.log(result);
       console.log('------------------------------------------------------------\n\n');  
});
 
connection.end();




var mysql  = require('mysql');  
 
var connection = mysql.createConnection({     
  host     : 'localhost',       
  user     : 'root',              
  password : '123456',       
  port: '3306',                   
  database: 'test' 
}); 
 
connection.connect();
 
var  addSql = 'INSERT INTO websites(Id,name,url,alexa,country) VALUES(0,?,?,?,?)';
var  addSqlParams = ['菜鸟工具', 'https://c.runoob.com','23453', 'CN'];
//增
connection.query(addSql,addSqlParams,function (err, result) {
        if(err){
         console.log('[INSERT ERROR] - ',err.message);
         return;
        }        
 
       console.log('--------------------------INSERT----------------------------');
       //console.log('INSERT ID:',result.insertId);        
       console.log('INSERT ID:',result);        
       console.log('-----------------------------------------------------------------\n\n');  
});
 
connection.end();




var mysql  = require('mysql');  
 
var connection = mysql.createConnection({     
  host     : 'localhost',       
  user     : 'root',              
  password : '123456',       
  port: '3306',                   
  database: 'test' 
}); 
 
connection.connect();
 
var modSql = 'UPDATE websites SET name = ?,url = ? WHERE Id = ?';
var modSqlParams = ['菜鸟移动站', 'https://m.runoob.com',6];
//改
connection.query(modSql,modSqlParams,function (err, result) {
   if(err){
         console.log('[UPDATE ERROR] - ',err.message);
         return;
   }        
  console.log('--------------------------UPDATE----------------------------');
  console.log('UPDATE affectedRows',result.affectedRows);
  console.log('-----------------------------------------------------------------\n\n');
});
 
connection.end();




var mysql  = require('mysql');  
 
var connection = mysql.createConnection({     
  host     : 'localhost',       
  user     : 'root',              
  password : '123456',       
  port: '3306',                   
  database: 'test' 
}); 
 
connection.connect();
 
var delSql = 'DELETE FROM websites where id=6';
//删
connection.query(delSql,function (err, result) {
        if(err){
          console.log('[DELETE ERROR] - ',err.message);
          return;
        }        
 
       console.log('--------------------------DELETE----------------------------');
       console.log('DELETE affectedRows',result.affectedRows);
       console.log('-----------------------------------------------------------------\n\n');  
});
 
connection.end();

添加key管理状态

<div v-for="(item,index) in result" :key="item.id">

不建议使用index作为key,让其为唯一

事件

v-on @

内联事件处理器

<template>
  <button @click="count++">加1</button>
  <p>Count:{{ count }}</p>
</template>

<script>
  export default {
    data() {
      return {
        count: 0
      }
    }
  }
</script>

方法事件处理器

<template>
  <button @click="addCount">加1</button>
  <p>Count:{{ count }}</p>
</template>

<script>
  export default {
    data() {
      return {
        count: 0
      }
    },
    methods:{
      addCount(){
        this.count+=1
      }
    }
  }
</script>

获取event对象

      addCount(e){
        this.count+=1
        console.log(e)
      }

传递参数

<template>
  <button @click="addCount('ok',$event)">加1</button>
  <p>Count:{{ count }}</p>
</template>

<script>
  export default {
    data() {
      return {
        count: 0
      }
    },
    methods:{
      addCount(msg,e){
        this.count+=1
        console.log(e);
        console.log(msg);
      }
    }
  }
</script>

事件修饰符

.stop阻止事件冒泡 .prevent阻止默认事件 .once .enter

<a @click.prevent="" href="…">abc
e.preventDefault() 也可以阻止默认事件