爱前端笔记

[toc]

目录

canvas

  • 概述:H5新增双闭合标签,它主要的功能是可以让我们写一些小游戏。
  • 资料:API手册

    一. canvas的基本使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
    * { margin: 0; padding: 0;}
    canvas { border: 1px solid black;}
    </style>
    </head>
    <body>
    <canvas width="600px" height="300px"></canvas>
    </body>

注意:canvas有默认的宽和高(300*150px),如果要改宽高,只能在行间样式中修改!canvas最终相当于是一张图片

  1. canvas绘制基本图形
    如果想在canvas上绘制图形,需要使用canvas2D上下文;

nodeJS

开门注

官网介绍:

  • Node.js是一个构建在Chrome浏览器V8引擎上的JavaScript运行环境;
  • Node.js使用了事件驱动、非阻塞I/O模型,这些都使它轻量、好用;
  • Node.js的包生态(npm),是世界上最大的开源生态系统。

1. JavaScript到底出了什么问题?

先说说异步I/O和同步I/O:绝大多数的网站I/O是非常多的,I就是input(数据的读取),O就是output(数据的写入),但I/O的时候CPU命令磁盘去做事情,此时CPU就闲置了。这种模式叫做同步I/O

  • 同步(synchronous):当系统遇见了一个需要耗费大量时间的事情时,选择死等。
  • 异步(Asynchronous):当系统遇见了一个需要耗费大量时间的事情时,不死等,先做后面的时期,耗时事情做完之后,执行回调函数。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var fs = require("fs");

    fs.readFile("./test.txt", function(err, data){
    console.log(data.toString()); // 后输出
    })

    var sum = 0;
    for(var i=0; i<=100; i++){
    sum += i;
    }
    console.log(sum); // 先输出

Node.js解决性能问题使用非常极端的思想:预期一堆服务员闲着,还不如一个服务员往死里用。

2. Node.js创建服务器(node.js)

1
2
3
4
5
6
7
8
9
10
11
12
// 读取内置模块http,这个模块是开发服务器用的
var http = require("http");
// 创建一个服务器
var server = http.createServer(function (req, res) {
// req表示请求,res表示响应
// 设置下行请求的头部信息(否则会出现乱码)
res.setHeader("Content-Type", "text/html;charset=UTF-8");
// 每个服务器都必须有一个end,即使为空!否则页面会一直处于loading状态,end里面必须是字符串或者二进制
res.end("<h1>我买了iPhone" + (3 + 4) + "</h1>")
});
// 监听
server.listen(3000);

运行:在文件所在目录下打开终端,使用下面的命令

1
node node.js

Node.js是一个让JavaScript运行在服务器端的开发平台,它让JavaScript的触角伸到了服务器端。但Node.js似乎和其他服务端语言比如PHP、ASP、JSP有点不同:

  • Node.js不是一种独立的语言,与PHP、JSP、Python、Ruby的“既是语言,也是平台”不同,Node.js使用JavaScript进行编程,运行在JavaScript引擎上(V8)
  • 与PHP、JSP等相比,Node.js跳过了Apache、Nginx、IIS等HTTP服务器,它自己不用建设在任何服务器软件之上。Node.js的许多设计理念与经典架构(LAMP)有着很大的不同,可以提供强大的伸缩能力.
  • Node.js自身哲学,就是花最小的硬件成本,追求更高的并发,更高的处理性能。
  • Node.js没有根目录的概念。
    1
    2
    3
    graph LR
    A(浏览器) -->|1.发送request请求|B[服务器2.nodejs程序在这里执行]
    B[服务器:2.nodejs程序在这里执行] -->|3.返回response响应|A(浏览器)

3. Node.js的特点:

  • 单线程特性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var http = require("http");
    var a = 0;
    var server = http.createServer(function (req, res) {
    a++;
    res.setHeader("Content-Type", "text/html;charset=UTF-8");
    // 每个服务器都必须有一个end,即使为空!否则页面会一直处于loading状态,end里面必须是字符串或者二进制
    res.end(a.toString());
    });
    // 监听
    server.listen(3000);

每次刷新a都会自增,说明没有新开进程,证明Node.js是单线程的

Node.js拥有JS的所有核心语法,包括ES6语法。但是Node.js没有BOM的东西,比如window对象等。

下面的程序一旦刷到6666,将抛出错误,然后程序会挂起,不能再被访问!侧面证明了Node.js是单线程的!

1
2
3
4
5
6
7
8
9
10
11
var http = require("http");

var server = http.createServer(function (req, res) {
var num = parsInt(Math.random() * 1000)
if(num === 6666){
throw new Error("错误!6666出现了!这个人的ip是" + req.connection.remoteAddress);
}
res.end("你的数字是" + num);
});
// 监听
server.listen(3000);

  • 异步I/O特性:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    var http = require("http"); // 创建服务器用的
    var fs = require("fs"); // 读取文件用的

    var ip = req.connection.remoteAddress;
    console.log(ip + "来了!开始读取文件!");

    var server = http.createServer(function (req, res) {
    // 来客人之后做的事情
    fs.readFile("./test.txt", function(err, data){
    res.end(data);
    console.log(ip + "读取文件完毕!");
    });
    });
    // 监听
    server.listen(3000);

可以看到一个ip开始读到读完之间,会插入别的ip开始读的情况!这就是异步I/O。==只要I/O越多,Node.js宏观上越并行==
wx20200312-140205@2x.png
而如果==计算越多,Node.js宏观上越不并行==,CPU将被某个线程单独占用!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var http = require("http"); // 创建服务器用的
var fs = require("fs"); // 读取文件用的

var ip = req.connection.remoteAddress;
console.log(ip + "来了!开始计算水仙花数!");
for(var i=1000; i<=9999; i++){
var ge = i % 10,
shi = parsInt(i / 10) % 10,
bai = parsInt(i / 100) % 10,
qian = parsInt(i / 1000) % 10;
var sum = Math.pow(ge,4) + Math.pow(shi,4) + Math.pow(bai,4) + Math.pow(qian,4);
if(sum == i){
console.log(ip + "算出了水仙花数!")
}
}
console.log(ip + "开始读取文件!");
var server = http.createServer(function (req, res) {
// 来客人之后做的事情
fs.readFile("./test.txt", function(err, data){
res.end(data);
console.log(ip + "读取文件完毕!");
});
});
// 监听
server.listen(3000);

wx20200312-140924@2x.png

Node.js适合I/O多的业务,例如:用户表单收集、考试系统、打分系统、聊天室、图文直播、提供JSON的API(为前台Angular等使用)……而不适合计算多的业务!

wx20200312-141558@2x.png

  • 事件驱动特性:事件驱动是Node.js的底层机制,我们只需要了解Node.js不会“上错菜”的原因就是事件驱动——事件环。事件环保证了Node.js可以高效准确的运行而不会紊乱。
    wx20200312-142532@2x.png

4. 路由机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var http = require("http"); 

var server = http.createServer(function (req, res) {
// 如果要根据用户访问的不同地址呈现不同显示,此时需要用req的url属性来进行判断
if(req.url == "/"){
res.end("首页");
}else if(req.url == "/music.html"){ // 实际上不存在这个页面,但只要输入这个路径,就会显示下面的内容,甚至路径可以伪装成任何样子
res.end("音乐频道");
}else if(req.url == "/news"){
res.end("新闻频道");
}else {
res.end("没有这个页面");
}
});
// 监听
server.listen(3000);

Node.js是没有像Apache那种真实物理文件映射关系的!这叫做顶层路由设计。能够制作顶层路由设计的语言目前比较流行的只有Node.js和Python

5. 模块

url模块、path模块、querystring模块

一个完整的URL包括querystring部分(就是GET请求查询字符串)、甚至hash部分。但req.url不包括hash(hash是前端标识,用于解决ajax无法回退等问题,所以在后端不用得到)

1
2
3
4
5
6
7
8
9
10
11
// 例如:http://127.0.0.1:3000/a.html?id=123#456

var http = require("http");

http.createServer(function (req, res) {
console.log(req.url);
// http://127.0.0.1:3000/a.html?id=123

res.end("");

}).listen(3000, "127.0.0.1"); // 直接写监听也可以,还可以限制访问的ip

而此时我们想得到querystring中的某一部分(l例如文件名),如果用正则提炼就太麻烦了,Node.js中提供了内置模块:url、path、querystring它们都可以服务于URL的识别。

  • url模块
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 例如:http://127.0.0.1:3000/a.html?id=123#456

    var http = require("http");
    var url = require("url");

    http.createServer(function (req, res) {
    // 将URL的字符串转为JSON对象
    var urlJson = url.parse(req.url);
    console.log(urlJson);
    res.end("");

    }).listen(3000, "127.0.0.1");

此时url的parse方法会将地址整理为一个对象,但无法正确识别protocol(协议)、host(主机名)、port(端口号)等等。在Linux系统下可以完全识别。
wx20200312-235536@2x.png
当有多个参数时,用url.parse(req.url, true)形成对象,方便存入数据库:

1
2
3
4
5
6
7
8
9
10
11
12
// 例如:http://127.0.0.1:3000/a.html?id=123#456

var http = require("http");
var url = require("url");

http.createServer(function (req, res) {
// 将URL的字符串转为JSON对象
var urlJson = url.parse(req.url, true); // 增加true
console.log(urlJson);
res.end("");

}).listen(3000, "127.0.0.1");

wx20200313-001127@2x.png

  • path模块

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 例如:http://127.0.0.1:3000/a.html?id=123#456

    var http = require("http");
    var url = require("url");
    var path = require("path");

    http.createServer(function (req, res) {
    // 将URL的字符串转为JSON对象
    var urlJson = url.parse(req.url, true); // 增加true
    // 得到文件路径
    var pathName = urlJson.pathname;
    // 得到拓展名
    var extName = path.extname(pathName);
    res.end("");

    }).listen(3000, "127.0.0.1");
  • querystring模块

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 例如:http://127.0.0.1:3000/a.html?id=123#456

    var http = require("http");
    var url = require("url");
    var path = require("path");
    var querystring = require("querystring");

    http.createServer(function (req, res) {
    // 将URL的字符串转为JSON对象
    var urlJson = url.parse(req.url);
    // 得到查询字符串
    var qs = urlJson.query;
    // 转为查询对象,和url.parse加上true非常类似
    var qsJson = querystring.parse(qs);
    res.end("");

    }).listen(3000, "127.0.0.1");

小项目:静态资源服务器 - 创建一个文件夹myweb,我们的程序能够自动为里面的文件、图片、css、js加上路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var http = require("http"); 
var fs = require("fs");
var url = require("url");
var path = require("path");
var querystring = require("querystring");

http.createServer(function (req, res) {
// 得到用户想要读取什么文件(输入的网址)
var pathName = url.parse(req.url).pathname;
// 真的去读取这个文件(在myweb里找到这个文件并呈现)
fs.readFile("./myweb/" + pathName, function(err,data){
if(err){
res.end("没有这个文件");
return;
}
res.end(data);
});
}).listen(3000, "127.0.0.1");

至此,静态资源服务器的框架已经完备,但还有几个点不够完善,比如下行文件中没有文件类型,所以借助++mime类型++修改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var http = require("http"); 
var fs = require("fs");
var url = require("url");
var path = require("path");
var querystring = require("querystring");

http.createServer(function (req, res) {
// 得到用户想要读取什么文件(输入的网址)
var pathName = url.parse(req.url).pathname;
// 得到拓展名
var extName = path.extname(pathName);
// 准备一个映射关系对
var mime = {
".jpg" : "image/jpeg",
".jpeg" : "image/jpeg",
".gif" : "image/gif",
".png" : "image/png",
".html" : "text/html;chartset=UTF-8",
".css" : "text/css",
".js" : "application/x-javascript"
}

// 真的去读取这个文件(在myweb里找到这个文件并呈现)
fs.readFile("./myweb/" + pathName, function(err,data){
if(err){
res.end("没有这个文件");
return;
}
// 检查是否属于已有的mime类型
if(mime.hasOwnProperty(extName)){
res.setHeader("content-type", mime[extName]);
}
res.end(data);
});
}).listen(3000, "127.0.0.1");

第二个问题:不能自动识别index文件。比如用户输入:http://127.0.0.1:3000/b 意思是要读取b文件夹中的index.html!解决思路就是如果用户输入了一个URL不存在拓展名,则自动补全/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
var http = require("http"); 
var fs = require("fs");
var url = require("url");
var path = require("path");
var querystring = require("querystring");

http.createServer(function (req, res) {
// 得到用户想要读取什么文件(输入的网址)
var pathName = url.parse(req.url).pathname;
// 得到拓展名
var extName = path.extname(pathName);
// 如果URL没有拓展名,则表示是文件夹,此时自动补全/index.html
if(!extName){
/*
此处还有问题!如果网址不是以/结尾,此时会造成浏览器识别文件路径层次有问题!
比如:
http://127.0.0.1:3000/a 和
http://127.0.0.1:3000/a/ 不一样!
对于同样一张图片,前者认为是同级目录下的图片,后者认为是a文件夹下的图片!所以要再次判断是否结尾是/,不是的话就需要重定向
*/
if(pathName.substr(-1) != "/"){
res.writeHead(302, { "Location" : pathName + "/" });
}

pathName += "/index.html";
}
// 准备一个映射关系对
var mime = {
".jpg" : "image/jpeg",
".jpeg" : "image/jpeg",
".gif" : "image/gif",
".png" : "image/png",
".html" : "text/html;chartset=UTF-8",
".css" : "text/css",
".js" : "application/x-javascript"
}

// 真的去读取这个文件(在myweb里找到这个文件并呈现)
fs.readFile("./myweb/" + pathName, function(err,data){
if(err){
res.end("没有这个文件");
return;
}
// 检查是否属于已有的mime类型
if(mime.hasOwnProperty(extName)){
res.setHeader("content-type", mime[extName]);
}
res.end(data);
});
}).listen(3000, "127.0.0.1");

还有一个问题,就是304状态码(not modified)。当文件没有改变时,拒绝传输文件!也就是当用户狂点刷新时,其实不发送请求。原理是通过session和cookie保存历史镜像,每次提交时进行比对,如果没有改变则不响应。

小结:
1.Node.js中的fs模块、mongdb模块基本上都是异步方法。一定要记住(当做规矩背),==异步方法不能通过return返回,不能通过等号来接收数据。必须通过回调函数传实参的模式来传输数据。==
2.内置模块用require无条件、无路径的引用,是Node.js天生就有的。

  • 自定义模块:每一个js文件。==Node.js、webpack、seajs等使用CMD(通用模块定义)规范==;Angular、requirejs等使用的是AMD(异步模块定义)规范。

01.js

1
2
require("./test.js");
console.log("我是01.js");

test.js

1
2
3
4
5
var fs = require("fs"); 
console.log("我是test.js");
fs.readFile("./pig.jpg", function(err, data){
console.log("图片读取完毕")
})

在01.js中引用test.js,会先打出:我是test.js,然后再打出:我是01.js,最后打出:图片读取完毕。说明:

  • require()谁就会运行谁
  • require(“./test.js”);中的”./“不能省略
  • require的js文件中如果有异步函数,将不会等待,先执行主文件之后的程序,等异步结束后回调函数会执行。
  • 如果A引用B,此时Node.js发现B又引用了A,则会阻止这次循环引用。

6. 作用域和暴露

  • exports暴露:当文件有多个东西对外暴露时,使用这个方法

01.js

1
2
require("./test.js");
console.log("我是01.js,我认识a么?" + a);

test.js

1
2
var a = 100; 
console.log("我是test的a" + a);

此时将报错,01.js打印出undefined,找不到a,因为==Node.js中每个js都是单独的作用域==(闭包),和DOM开发不同,浏览器中var一个a此时a会自动成为window对象的属性,此时js文件和js文件可以共享作用域;但是Node.js中每个js文件天生是隔离作用域的,所以想要访问其内部的变量或方法,必须先通过exports.xx = xx暴露出去

01.js

1
2
3
4
5
6
var test = require("./test.js");
console.log("我是01.js,我认识a么?" + test.a);
console.log("我是01.js,我认识b么?" + test.b);

var result = test.zonghe();
console.log("总和是" + result);

test.js

1
2
3
4
5
6
7
8
9
10
var a = 100; 
var b = 200;

exports.a = a;
exports.b = b;

function zonghe(){
return a + b + c;
}
exports.zonghe = zonghe;
  • module.exports暴露:当文件只有一个东西对外暴露时,用这个方法

01.js

1
2
3
4
5
var People = require("./People.js");

// var xiaoming = new People.People("小明","男",12);
var xiaoming = new People("小明","男",12);
xiaoming.sayHello();

People.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function People(name, sex, age){
this.name = name;
this.sex = sex;
this.age = age;
}
People.prototype.sayHello = function(){
console.log("你好,我叫" + this.name + "我今年" + this.age + "我是" + this.sex + "的")
}

// exports.People = People;
// 如果这里用这种形式暴露的话,那么01.js中用来接收的People会直接替换exports,所以在使用时才会出现People.People这种很怪的方式

module.exports = People;
// 使用module.exports时等号右边的东西,将自动传给01.js中用来接收的var People

7. 神奇的node_modules文件夹

如果我们写了一个引用没有”./“,则说明引用的是node_modules文件夹里的东西

1
var People = require("People.js");

node_modules文件夹只要存在于要引用它的js文件的祖先路径中,就可以直接引用,无视路径层级

8. npm的世界

Node.js的开发者们希望全世界的程序猿都可以贡献自己的代码,避免重复造轮子,所以主导了一个社区,叫做npm(node package management, node包管理器)

  • npm的使用
    官网:https://www.npmjs.com
    淘宝镜像:http://npm.taobao.org
    我们可以到npm上面直接寻找我们想要的模块,然后直接npm install就可以了
  • 使用package.json来管理依赖
    npm有一个创造性的举动,可以让开发者声明自己的项目的全部依赖。在项目目录下创建一个叫做package.json的文件来记录。初次创建项目时,可以在项目文件夹下,通过
    1
    npm init

命令来初始化一个package.json文件,而使用–save命令,在安装依赖的同时,会把依赖写进package.json文件

1
npm install xxx --save

安装时也可以强制安装某个版本

1
npm install xxx#^1.0.0 --save

关于版本号的常用符号:
|符号|对应的版本号含义|
|:–|:–|
|确数(1.0.2)|确定的某个版本|
|>、>=、<、<=|高于/低于…某个版本|
|~|大约近似等于某个版本,如果有就一定用这个版本,没有就用最近的|
|^|寻找和某个版本兼容的版本,如果有就一定用这个版本,没有就用最近的|
|*|匹配任何版本|
|laste|寻找最新版本|

  • 全局安装淘宝镜像
    1
    npm install xxx -g // 全局安装某个包

一些CLI(命令行程序)、工程化的东西安装在全局

1
npm install -g cnpm --registry=https://registry.npm.taobao.org

9. GET和POST请求

先安装一个小型服务器

1
2
cnpm install serve-static --save
cnpm install finalhandler --save

然后去淘宝镜像上根据包名查找对应的API,抄一些用法过来,详见nootbook/get&post

  • GET请求:

01.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
var finalhandler = require('finalhandler')
var http = require('http')
var serveStatic = require('serve-static')
var url = require("url")
var fs = require("fs")

// 配置静态资源服务器
var serve = serveStatic('public', { 'index': ['index.html', 'index.htm'] })

// Create server
var server = http.createServer(function onRequest(req, res) {
// 路由
var pathName = url.parse(req.url).pathname;
if (pathName == "/addStudent") {
// 拿到GET请求参数,也就是那到地址栏中的东西
var queryJSON = url.parse(req.url, true).query;
// 整理数据
var data = "姓名" + queryJSON.name + "\n";
data += "年龄" + queryJSON.age + "\n";
data += "性别" + queryJSON.sex + "\n";
// 写入文件
fs.writeFile("./student_data/" + queryJSON.name + ".txt", data, function(err, data) {
if (err) {
res.end("cuowu");
return;
} else {
res.end("chenggong");
}
})

return;
// 注意必须要加return,不然会报404错误!是由于不返回的话会再次匹配静态资源造成的
}

// 使用静态资源,将public文件夹下的内容静态化出来。这个要放在下面。
serve(req, res, finalhandler(req, res));
})

// Listen
server.listen(3000)
console.log("服务器已经运行在3000端口");

public/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>姓名:<input type="text" name="name" /></p>
<p>年龄:<input type="text" name="age" /></p>
<p>性别:
<label><input type="radio" name="sex" value="男" />男</label>
<label><input type="radio" name="sex" value="女" />女</label>
</p>
<p><input type="button" value="按我发出GET请求" id="btn1" /></p>
<p><input type="button" value="按我发出POST请求" id="btn2" /></p>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript">
$("#btn1").click(function() {
// 读取表单
var name = $("input[name=name]").val();
var age = $("input[name=age]").val();
var sex = $("input[name=sex]").val();

// 发送请求
$.get("/addStudent", {
name : name,
age : age,
sex : sex
}, function(data) {
if (data == "chenggong") {
alert("恭喜,学生已成功添加!")
}else {
alert("对不起,服务器错误!")
}
})
})
$("#btn2").click(function () {
// 读取表单
var name = $("input[name=name]").val();
var age = $("input[name=age]").val();
var sex = $("input[name=sex]").val();

// 发送请求
$.post("/addStudent", {
name: name,
age: age,
sex: sex
}, function (data) {
if (data == "chenggong") {
alert("恭喜,学生已成功添加!")
} else {
alert("对不起,服务器错误!")
}
})
})
</script>
</body>
</html>
  • POST请求

02.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
演示POST请求的获得
*/
var finalhandler = require('finalhandler')
var http = require('http')
var serveStatic = require('serve-static')
var url = require("url")
var fs = require("fs")
var querystring = require("querystring")

// 配置静态资源服务器
var serve = serveStatic('public', { 'index': ['index.html', 'index.htm'] })

// Create server
var server = http.createServer(function onRequest(req, res) {
// 路由
var pathName = url.parse(req.url).pathname;
if (pathName == "/addStudent") {
// 定义了一个post变量,用于暂存请求体的信息
var content = '';

// post请求经常会很长,此时会分段传送,大约每段800k左右一个HTTP报文段
// 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
req.on('data', function (chunk) {
// 将段落合并
content += chunk;
});

// 当所有数据发送完毕后,会触发end事件,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
req.on('end', function () {
content = querystring.parse(content);

// 整理数据
var data = "姓名" + content.name + "\n";
data += "年龄" + content.age + "\n";
data += "性别" + content.sex + "\n";
// 写入文件
fs.writeFile("./student_data/" + content.name + ".txt", data, function (err, data) {
if (err) {
res.end("cuowu");
return;
} else {
res.end("chenggong");
}
})

res.end("chengogng");
});


return;
}

// 使用静态资源。这个要放在下面。
serve(req, res, finalhandler(req, res));
})

// Listen
server.listen(3000)
console.log("服务器已经运行在3000端口");

10. formidable模块:npm上可以下载一个formidable的模块,用来处理post请求。甚至可以处理图片、zip文件等的上传。

1
npm install formidable --save // 安装依赖

具体代码详见03.js和upload.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/*
演示POST请求通过formidable模块来处理参数
*/
var finalhandler = require('finalhandler')
var http = require('http')
var serveStatic = require('serve-static')
var url = require("url")
var fs = require("fs")
var querystring = require("querystring")
const formidable = require('formidable')
const path = require('path')

// 配置静态资源服务器
var serve = serveStatic('public', {
'index': ['index.html', 'index.htm']
})

// Create server
var server = http.createServer(function onRequest(req, res) {
// 路由
var pathName = url.parse(req.url).pathname;

if (pathName == "/shangchuan") {
// 照抄npm.taobao.org上的API
const form = formidable({
multiples: true
});

// 设置上传的文件存放在哪里
form.uploadDir = "./uploads"

form.parse(req, (err, fields, files) => {
// fields 表示普通控件
// files 表示文件控件

// 检测是否有文件
if (!files.touxiang) {
return
}
// 检测是否有上传文件
if (!files.touxiang.name) {
res.end("请选择文件")
return
}
// 得到拓展名
var extname = path.extname(files.touxiang.name);
// 为上传的文件加上拓展名
fs.rename(files.touxiang.path, files.touxiang.path + extname, function() {
res.end("上传成功")
})
});


return;
}

// 使用静态资源。这个要放在下面。
serve(req, res, finalhandler(req, res));
})

// Listen
server.listen(3000)
console.log("服务器已经运行在3000端口");

待补充(两个大包)

11. Express.js框架:

解决了哪些问题

  • 路由不方便制作,尤其是正则表达式路由
  • 静态资源服务不方便
  • 页面呈递不方便,没有模板引擎

官网:www.expressjs.com.cn

1
cnpm install express --save

基本使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var express = require("express");
var app = express();
// 中间件(注意顺序)
app.get("/", function(){
res.send("我是首页");
})
app.get("/music", function(){
res.send("音乐频道");
})
app.get("/news", function(){
res.send("新闻频道");
})
app.get("/student/:xuehao", function(){
if(/^[\d]{6}$/.test(req.params.xuehao)){
res.send("学生频道,学号" + req.params.xuehao);
}else{
res.send("学号有误,应该是6位数字");
}
})
app.get("/student/:123", function(){
res.send("123是班长" + req.params.xuehao);
// 这个中间件将不会被匹配到,因为上面匹配到了学号就不会再往下走了
})
// 静态化public文件夹,无论get还是post都能使用
app.use(express.static("./public"));
// 将public文件夹中的东西映射到jingtai文件夹中(访问路径也变为/jingtai/xxx)
app.use("./jingtai", express.static("./public"));

app.listen(3000);

中间件特点:

  • 输出使用res.send()而不是res.end()
  • 自动使用pathname与/news进行比较,也就是说会自动过滤掉querystring、hash等等
  • 可以用:来引导一个变量,此时特别方便做一个正则的路由,并用req.params.xxx获取

需求:当访问 / 时,其实真正想访问的页面是public/haha.html

1
2
3
4
5
...
app.get("/", function(){
res.sendFile(__dirname + "/public/haha.html");
})
...

==res常用的函数是send和sendFile。sendFile表示发送一个页面给用户。注意sendFile必须使用绝对路径当做参数,而__dirname表示当前这个js文件的绝对路径==

12. 模板引擎:express可以象PHP一样使用后台语言模板,此时最好用的模板引擎叫做ejs模板引擎。

API:https://npm.taobao.org/package/ejs

1
cnpm install ejs --save

基本使用方法:

01.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var express = require("express");
var app = express();

// 设置默认的模板引擎,此时express将帮你引入ejs,所以一定要提前装好依赖
app.set("view engine", "ejs");

app.get("/", function(){
res.render("shouye",{
"dongxi" : "八个手机",
"qian" : 1000 * 8
});
})

app.listen(3000);

此时当用户访问 / 的时候,会自动使用views文件夹里的shouye.ejs文件当做模板。字典就是后面传入的json。

views/shouye.ejs

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>我买了<% dongxi %>,花了<% qian %>元</h1>
</body>
</html>

注意:ejs就是html,写法完全一样!

13. MVC设计模式:

MVC是一种使用Model(模型)、View(视图)、Controller(控制器)设计创建Web应用程序的模式。

  • Model(模型)是应用程序中处理应用程序数据逻辑的部分,通常模型对象负责在数据库中存取数据。
  • View(视图)是应用程序中处理数据显示的部分,通常视图是依据模型数据创建的。
  • Controller(控制器)是应用程序中处理用户交互的部分,通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
    1
    2
    3
    4
    graph TB
    A(Controller) -->B(Model)
    B(Model) -->A(Controller)
    A(Controller) -->C(View)

因数计算器和点餐系统代码详见作业

14. MongoDB芒果数据库

NoSQL简介

  • SQL就是Structor Query Language(结构化语言)。MySQL、Oracle、SQL Server数据库都是SQL数据库,在大数据时代有些场景使用它们显得太笨重,因为SQL有一个非常大的缺点,就是限制字段:
    1
    比如现在数据库中已经有10万条数据了(在今天10万条都不算大数据),如果想从下一条数据开始增加字段,此时之前的10万条数据都需要被更改!表的字段是不能自由更改的,不能某一个条目有一些字段,另外的条目没有!

而SQL的优势在于能够轻松执行复杂查找,例如主从关系查找等。但在大数据时代SQL的优势在衰减(基本都是简单查询),而缺点在被放大。所以此时NoSQL(Not Only SQL)这种==非关系型数据库==应运而生。

NoSQL中没有字段的概念,每个条目可以自由设置字段。

MongoDB安装与配置详见踩坑之各种报错篇,创建好数据库后就可以进行各种指令操作数据库了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> use student
// 创建名为student的数据库,此时可以用db来代表这个数据库

db.banji01.insert({"name":"小明","age":12})
// 在student数据库(此处用db代表)中创建banji01集合(表),并插入一条数据(数据用json格式)

db.banji01.find();
// 查找banji01表中的数据(会为你填上随机数的id)

db.banji01.insert({"name":"小红","age":12})
db.banji01.insert({"name":"小强","age":11})

db.banji01.find({"age":12});
// 有条件查找

15. Node.js和MongoDB的连接

API

  • 先安装依赖
    1
    cnpm install mongodb --save

文档与集合的关系:

  • 文档
    1584430515111.jpg
  • 集合
    wx20200317-153442@2x.png

在REPL环境中最常用的命令语句,除了上面用到的,还有:

1
2
3
> use student // 使用student数据库,没有就创建
> show dbs // 显示所有数据库列表
> show collections // 显示当前数据库的所有集合列表

增删改查:API

  • 增(mongodb/01.js)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    const MongoClient = require('mongodb').MongoClient;
    // const assert = require('assert'); // 断言

    // 连接的url
    const url = 'mongodb://localhost:27017';

    // 数据库名
    const dbName = 'student';

    // 建立一个新连接
    const client = new MongoClient(url);

    // 用connect方法连接服务
    client.connect(function (err, client) {
    // assert.equal(null, err); // 断言验证
    if (err) {
    console.log("数据库连接失败!")
    return
    }
    console.log("数据库连接成功");

    // 用db代替数据库名
    const db = client.db(dbName);

    // 在指定的表内插入一条数据
    db.collection('banji01').insertOne({
    "name": "刘备",
    "age" : 12
    }, function (err, r) {
    // assert.equal(null, err); // 断言验证
    // assert.equal(1, r.insertedCount); // 断言验证
    if (err) {
    console.log("数据插入失败!")
    return
    }
    console.log("成功插入了" + r.insertedCount + "条数据")

    // 插入多条数据的方法
    db.collection('banji01').insertMany([{ a: 2 }, { a: 3 }], function (err, r) {
    assert.equal(null, err);
    assert.equal(2, r.insertedCount);
    // 关闭数据库
    client.close();
    });
    });
    });
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    const MongoClient = require('mongodb').MongoClient;

    const url = 'mongodb://localhost:27017';

    const dbName = 'myproject';

    const client = new MongoClient(url);

    client.connect(function(err, client) {
    assert.equal(null, err);
    console.log("Connected correctly to server");

    const db = client.db(dbName);

    const col = db.collection('removes');
    // Insert multiple documents
    col.insertMany([{a:1}, {a:2}, {a:2}], function(err, r) {
    assert.equal(null, err);
    assert.equal(3, r.insertedCount);

    // Remove a single document
    col.deleteOne({a:1}, function(err, r) {
    assert.equal(null, err);
    assert.equal(1, r.deletedCount);

    // Update multiple documents
    col.deleteMany({a:2}, function(err, r) {
    assert.equal(null, err);
    assert.equal(2, r.deletedCount);
    client.close();
    });
    });
    });
    });
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    db.collection('banji01').find({"name":"小明"}).toArray(
    // 注意与其他的不同,这里find的结果要先转成数组
    function(err,results){
    if (err) {
    console.log("数据查询失败!")
    return
    }
    console.log(results) // 打印出查询到的条目
    db.close()
    }
    )

多个查询条件时,例如寻找姓名是小明且年龄为12的学生,用“ ,”隔开。

1
2
3
4
5
6
7
8
9
10
11
12
13
db.collection('banji01').find({
"name":"小明",
"age":12
}).toArray(
function(err,results){
if (err) {
console.log("数据查询失败!")
return
}
console.log(results) // 打印出查询到的条目
db.close()
}
)

查询条件中的大于、小于条件

1
2
3
4
5
6
7
8
9
10
11
12
13
db.collection('banji01').find({
"age":{$gt : 12} // {$gt : 12}表示大于12
//"age":{$lt : 12} // {$lt : 12}表示大于12
}).toArray(
function(err,results){
if (err) {
console.log("数据查询失败!")
return
}
console.log(results) // 打印出查询到的条目
db.close()
}
)

或逻辑:用$or来引导一个数组,里面是或的条件。例如寻找年龄大于12岁的男生或者年龄小于11岁的女生

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
db.collection('banji01').find({
{$or : [
{ "age":{$gt:12} , "sex": "男"},
{ "age":{$lt:11} , "sex": "女"}
]}
}).toArray(
function(err,results){
if (err) {
console.log("数据查询失败!")
return
}
console.log(results) // 打印出查询到的条目
db.close()
}
)

  • 改:分为增量改和彻底改两种。彻底改用处不大,就是把一条数据完全改成另一条数据,此举危险!
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    db.collection('banji01').updateOne(
    {"name": "刘备"},
    {"age" : 12}
    , function (err, r) {
    if (err) {
    console.log("数据修改失败!")
    return
    }
    console.log("成功")
    // 此时"name": "刘备"会被替换成"age" : 12
    // "name": "刘备"这个属性就没了!
    client.close();
    });

增量改:用$set引导

1
2
3
4
5
6
7
8
9
10
11
12
db.collection('banji01').updateOne(
{"name": "刘备"},
{$set:{"age" : 12}}
, function (err, r) {
if (err) {
console.log("数据修改失败!")
return
}
console.log("成功")
// 此时刘备的age会被替换成12!
client.close();
});

16. MongoDB

数据库 = 存储东西 + 数据库操作API。

React

一、Dashboard是什么

dashboard即仪表盘项目,通俗地讲,就是xxx管理平台,特点:

  1. 单页面应用(SPA,single page application):以#号为分隔,#号前不变,#号后发生改变,也就是说网页没有发生跳转,而是DOM的整体上树、下树。这样做的好处是,让本地变量可以在本地持久的使用。
  2. 组件化:
  3. 所有的DOM元素都是动态上树的,页面上没有了HTML清单,所有的部件都是组件,组件套组件,再集体被js上树。

    综上所述,React和Vue,包括Angular,就是提供组件化开发的,单页面应用的,动态上树的模块化开发框架

    二、webpack构建工具

    解决问题:webpack是Node.js的工作流工具。在它推出之前,前端不认识exports暴露出来的东西,也不认识require这个引入命令,虽然es6推出了export暴露和import引入语法,但仍不能被浏览器识别。为了解决这个问题,之前推出了commonjs和seajs,后来都被webpack取代,由于commonjs是最先提出来的,所以此类规范被称为CMD(通用模块定义)规范。

  4. 安装:

    1
    2
    npm install -g webpack
    npm install -g webpack-cli
  5. webpack的基本使用

    main.js

    1
    2
    3
    import {mianji} from "./yuan.js"
    }
    alert(mianji(10));

yuan.js

1
2
3
export const mianji = function(r){
return 3.14 * r * r;
}

index.html想要弹出圆面积,就必须引用这两个符合CMD规范的js文件,但此时用webpack命令

1
webpack main.js -o all.js

就会生成all.js这个打包后的文件,此时webpack做了三个事情:

  • 从main.js出发,顺着import链寻找每一个依赖的js文件
  • 将每一个js文件智能打包。如果某个js文件一个export都没用,将不会被打包。
  • 去import、export化,也就是说all.js是IE8兼容的。
  1. 使用webpack.config.js来指导webpack的工作
    webpack配置API
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const path = require('path');

    module.exports = {
    mode: "production", // 生产环境

    entry: "./app/entry", // 入口文件,从这里应用程序开始执行webpack 开始打包

    output: { // webpack出口文件

    path: path.resolve(__dirname, "dist"), // string
    // 所有输出文件的目标路径
    // 必须是绝对路径(使用 Node.js 的 path 模块)

    filename: "bundle.js", // string
    // 打包成bundle.js文件
    },
    watch: true // 默认为false,开启后实时监控webpack的修改并自动更新!
    }

配置好后,只需在终端执行下面语句,即可实现修改文件自动打包(终端不能关闭)

1
webpack

三、ES6中的暴露和导入

  1. 暴露(export const),注意一定要有const!

    yuan.js

    1
    2
    3
    export const function mianji(r){
    return 3.14 * r * r;
    }
  2. 导入(import{xx,xx} from ‘./xxx’),引入的名字和暴露的名字要一致

    index.html

    1
    2
    3
    import {mianji} from './yuan.js'

    alert(mianji(10));
  3. 命名空间:解决引入js文件暴露方法同名问题

    yuan.js

    1
    2
    3
    export const mianji = function(r){
    return 3.14 * r * r;
    }

fang.js

1
2
3
export const mianji = function(r){
return r * r;
}

index.html

1
2
3
4
5
import * as yuan from './yuan.js'
import * as fang from './fang.js'

alert(yuan.mianji(10));
alert(fang.mianji(10));

  1. 默认暴露:如果一个js文件是一个类,此时我们不希望有命名空间,就用export default来暴露

    people.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    export default class People{ // 定义类固定写法,注意没()
    constructor(name,age,sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
    }
    changge(){ // 类中的方法要这样写!
    alert(`我是${this.name},我今年${this.age}岁啦!`)
    }
    }

index.html

1
2
3
4
import People from './people.js'

var xiaoming = new People("小米",12,"男");
xiaoming.changge();

四、webpack的高级使用

  1. babel-loader:babel是用来翻译高级语法的,需要通过-g安装的工具,需要用.babelrc文件进行指导。如果想让webpack在打包过程中顺便对每一个js文件用babel进行翻译,就需要loader(加载器)来帮助。
    1
    2
    3
    4
    // 安装依赖
    cnpm i --save-dev @babel/core
    cnpm i --save-dev babel-loader
    cnpm i --save-dev @babel/preset-env
  • babel-core:表示babel的核心。
  • babel-loader:表示babel的加载器。
  • babel-preset-env:表示babel的预处理器,让babel对ecmascript new version进行翻译。

此处需要特别注意版本问题,原则上babel-loader 8.x对应babel-core 7.x 而babel-loader 7.x对应babel-core 6.x!所以如果按照传统安装方式,很可能babel-loader和babel-core版本不对应产生报错Error: Cannot find module ‘@babel/core’ 而 webpack.config.json中的设置也有所改变:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const path = require('path');

module.exports = {
mode: "production", // "production" | "development" | "none"

entry: "./app/entry",

output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js"
},

module: { // 关于模块配置

rules: [ // 模块规则(配置 loader、解析器等选项)

{
test: /\.jsx?$/, // 正则以.js结尾的文件
include: [
path.resolve(__dirname, "app") // 包括app文件夹
],
exclude: [
path.resolve(__dirname, "node_modules") //不包括node_modules文件夹
],
loader: "babel-loader",
options: {
// presets: ["env"] 此处变为:
presets: ["@babel/preset-env"]
}
}
]
}
}

  1. webpack-dev-server
    1
    cnpm i -g webpack-dev-server

webpack-dev-server会创建一个虚拟的服务,避免开发阶段频繁修带来的磁盘频繁读写,造成对磁盘的伤害。所以目录结构更改为:

  • project
    • www
      • app
        • fang.js
        • yuan.js
        • people.js
      • index.html
    • node_modules
    • package.json
    • webpack.config.js

此时配置文件webpack.config.js变为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const path = require('path');

module.exports = {
mode: "development",
entry: "./www/app/entry", // 增加www/
output: {
path: path.resolve(__dirname, "www/dist"), // 增加www/
filename: "bundle.js",
publicPath: "/xuni" // 虚拟打包路径
},
module: {
rules: [
{
test: /\.jsx?$/,
include: [
path.resolve(__dirname, "www/app") // 增加www/
],
exclude: [
path.resolve(__dirname, "node_modules")
],
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
}
]
}
}

以上配置注意路径问题,只有一个加./的,其余都是www/ ;然后就可以这样启动项目:

1
webpack-dev-server --content-base ./www --port 8080

  • –content-base表示以./www文件夹作为一个根目录
  • –port表示端口号是8080
    webpack-dev-server在进行两个事情:
  • 在打包js文件(就是webpack的事情)
  • 静态化www文件夹,等于帮我们写了一个app.use(express.static(“www”));

    注意:index.html中引入的文件路径要换成:

    1
    <script src="xuni/bundle.js"></script>

项目的物理磁盘上并没有xuni文件夹,而是通过webpack-dev-server将/xuni/bundle.js文件路由到了打包的文件,这样做的好处是频繁更改也不毁磁盘,而且会自动更新!

但启动项目每次都要写“webpack-dev-server –content-base ./www –port 8080”太麻烦了,此时我们可以通过更改package.json(身份证)文件的配置来进行简化:

package.json

1
2
3
"scripts" : {
"dev" : "webpack-dev-server --content-base ./www --port 8080"
}

这样就可以通过以下命令来启动项目:

1
npm run dev

React配置和起步

React需要建立在webpack + babel-loader上

依赖

1
2
3
npm i --save react
npm i --save react-dom
npm i --save babel-preset-react

package.json的options需要增加一项:

1
2
3
options: {
presets: ["@babel/preset-env","@babel/preset-react"]
}

Vue

一、简介

vue提供了一种“引包法”,初学者在这个模式下学习基本语法,不需要webpack,不需要CMD打包

二、启动

vue的包:https://cn.vuejs.org/js/vue.js,使用方式如下:

1
2
3
4
5
6
7
8
9
10
11
<body>
<div id="app">
<h1>{{1 + 1}}</h1>
</div>
<script type="text/javascript" src="./jslib/vue.js"></script>
<script>
new Vue({
el : "#app"
})
</script>
</body>

这里是唯一的一次书写new运算符。这是vue的语法,因为vue是一个构造函数,注意它并不是组件的构造函数,就是启动语法而已。

React中任何一个组件都是一个class(类),并且这个类继承于React.Component。当你放标签的时候,相当于实例化了这个类。
Vue也是一样,任何一个组件也是一个类。但Vue有一个非常大的特点:++语法隐藏底层细节++

三、MVVM特性

  1. 清单式语法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <body>
    <div id="app">
    <h1>{{a}}</h1>
    <button @click="add()">按我+1</button>
    </div>
    <script type="text/javascript" src="./jslib/vue.js"></script>
    <script>
    new Vue({
    // 运行点
    el : "#app",
    // 数据
    data: {
    a : 100
    }
    // 方法
    methods: {
    add(){
    this.a++
    }
    }
    })
    </script>
    </body>
  2. 双向绑定机理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <body>
    <script>
    var obj = {
    a : 8
    }

    Object.defineProperties(obj, {
    "a" : {
    set(){
    alert("改了!快通知视图跟着变!")
    }
    }
    })
    </script>
    </body>

四、指令

指令,即标签身上的属性,只是这些属性有特殊性、功能性

  1. v-if和v-show
  • v-if决定元素是否上树
  • v-show决定元素是否显示

如果需要触发组件的生命周期钩子函数,此时让组件携带v-if,反之用v-show

  1. v-for:用来实现循环某个节点,循环节点必须绑key
    1
    2
    3
    4
    5
    <ul>
    <li v-for="(item, index) in arr" v-bind:key="index">
    {{ index }} - {{ item }}
    </li>
    </ul>

特别的,可以循环自然数

1
<p v-for="item in 5">{{ item }}</p>

99乘法表

1
2
3
4
5
6
7
8
9
<table>
<tr v-for="i in 9">
<td v-for="j in 9">
<span v-show="i>=j">
{{ i }} * {{ j }} = {{ i*j }}
</span>
</td>
</tr>
</table>
  1. v-bind(==重难点==)

v-bind指令可以让任何W3C属性变“动态”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body>
<div id="app">
<input tyoe="text" v-bind:value="a" />
</div>
<script type="text/javascript" src="./jslib/vue.js"></script>
<script>
new Vue({
el : "#app",
data: {
a : 100
}
})
</script>
</body>

注意:v-bind:xxx=”…” 冒号里面已经是动态的了,所以在里面的写法要和js语法保持一致!特别注意连字符!

1
2
3
4
<input tyoe="text" v-bind:value="a" />
<input tyoe="text" v-bind:value="3+5" />
<input tyoe="text" v-bind:value="'./images/' + a + '.jpg'" />
<input tyoe="text" v-bind:value="`./images/${a}.jpg`" />
  1. v-on:事件监听
  2. v-model:双向绑定

调色板案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>调色板</title>
<style>
.box{width: 200px; height: 200px; border: 1px solid #000;}
</style>
</head>
<body>
<div id="app">
<div class="box" :style="`background-color:rgb(${r},${g},${b})`"></div>
<p>
<input type="range" :min="0" :max="255" v-model="r" />
<input type="number" :min="0" :max="255" v-model="r" />
{{ r }}
</p>
<p>
<input type="range" :min="0" :max="255" v-model="g" />
<input type="number" :min="0" :max="255" v-model="g" />
{{ g }}
</p>
<p>
<input type="range" :min="0" :max="255" v-model="b" />
<input type="number" :min="0" :max="255" v-model="b" />
{{ b }}
</p>
</div>

<script type="text/javascript" src="jslib/vue.js"></script>
<script type="text/javascript">
new Vue({
el : "#app",
data : {
r : 100,
g : 200,
b : 123
}
})
</script>
</body>
</html>
  1. computed和methods
0%