现在才来看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() 也可以阻止默认事件