提交 c7923152 编写于 作者: A a1511870876

doc/docx-->md

上级 89e5fe66
## 一、JavaScript模块化的概念解读(面试必问)
2009年,Nodejs 诞生!这个服务器端的 JavaScript 采用模块化的写法很快征服了浏览器端的 JSer 。牛人们纷纷仿效,各种写模块的规范也是层出不穷。CommonJS 想统一前后端的写法,AMD 则认为自己是适合浏览器端的。国内的 CMD 非常成熟。
起源于nodejs,把代码打包成模块,采用require引用。
AMD是RequireJS在推广过程中对模块定义的规范化产出。
异步加载模块,以来前置,提前执行。
Define定义模块define([‘require’,’foo’],function(){return});
Require加载模块(以来前置)require([‘foo’,’bar’],function(foo,bar){});
CMD是SeaJS在推广过程中对模块定义的规范化产出。
Define定义exports导出define(function(require,exports,module){});
Module上存储了当前模块的一些对象。
Require(./a)直接引入。Requeir.async异步引入。
同步加载,依赖就近,延迟执行。
类似的还有CommonJS Modules/2.0规范。
## 二、JavaScript数据推送
数据推送在当下非常火热,我们的手机每天都能收到来自APP的各种消息,JavaScript数据推送主要致力于webapp的在线推送服务,不用我们每次都像服务器去发送Ajax请求而主动从Server端推送数据到本地。在早期必须保持着一个链接不放,或者通过前端不停的向后端发送请求,H5更新后有了WebSocket大大改善了双向和单向推送数据的便利性。
### 1.Comet:基于HTTP长链接的服务器推送技术
基于 HTTP 长连接的服务器推送技术,Comet 是一种 Web 应用架构。服务器端会主动以异步的方式向客户端程序推送数据,而不需要客户端显式的发出请求。Comet 架构非常适合事件驱动的 Web 应用,以及对交互性和实时性要求很强的应用,如股票交易行情分析、聊天室和 Web 版在线游戏等。
### 2.基于WebSocket的推送方案
基于WebSocket 的推送方案,在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 flex ajax bridge,可以在javascript中使用这两项功能. 可以预见,如果websocket一旦在浏览器中得到实现,将会替代上面两项技术,得到广泛的使用.面对这种状况,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并达到实时通讯。
### 3.SSE(Server-Send Event):服务器推送数据的新方式
服务器推送数据的新方式SSE,传统的网页都是浏览器向服务器"查询"数据,但是很多场合,最有效的方式是服务器向浏览器"发送"数据。比如,每当收到新的电子邮件,服务器就向浏览器发送一个"通知",这要比浏览器按时向服务器查询(polling)更有效率。服务器发送事件(Server-Sent Events,简称SSE)就是为了解决这个问题,而提出的一种新API,部署在EventSource对象上。目前,除了IE,其他主流浏览器都支持。
## 三、JavaScript中
obj array 是js对象 作为函数参数时为按引用传递
string number boolean作为函数参数时为按值传递
### 学习交流
项目同时部署在阿里云,访问地址[www.keepforward.xyz:3000](www.keepforward.xyz:3000)
gihub地址:[https://github.com/a1511870876/myblog](https://github.com/a1511870876/myblog)欢迎star
一些学习分享,大家共同交流,地址[https://github.com/a1511870876/studyFiles](https://github.com/a1511870876/studyFiles)
### 写在前面
Koa使用了ES6规范的generator和异步编程是一个更轻量级Web开发的框架,Koa 的先天优势在于 generator。由于是我个人的分享交流,所以Node基础、ES6标准、Web开发基础以及Koa的"Hello World"程序都不在讨论,希望各位小伙伴提出意见和指导。
PS:Koa 内核中没有捆绑任何中间件,但不用担心,Koa 拥有极其强悍的拓展性,正文所有中间件都可以在npm官网下载安装,但国内域名安装会有一些限制,提供一个国内镜像安装方法,速度非常快,在直接npm模块失败的时候非常好用,使用npm --registry=http://registry.npmjs.org install XXXXX –XX 命令安装,只需要在install后面加上要安装的中间件名称和相应的参数即可。
### 一、使用Koa搭建Web项目流程
**1、Koa项目创建**
个人认为不管任何框架,Web项目搭建必需的几个方面,页面、中间件、路由、会话和存储、日志、静态文件指定,以及错误的处理。当然,网站开发不止这些东西,还有许多主题,比如实时通讯,搜索引擎架构,权限控制,邮件优先队列,日志记录分析,对Web开发还刚刚入门属于菜鸟级别,这里就不做深入的讨论了。了解Express框架的小伙伴一定知道Express的部署过程,不管是通过express-generator生成还是WebStorm等编译器直接创建,它的目录结构大概是这样的:
```
|——app.js
|——bin
|——node_modules
|——package.json
|——public
|——routes
|——views
```
*app.js,是程序启动文件
*bin,存放执行程序
*node_modules,存放项目依赖库
*package.json,是配置和一些相关信息
*public,存放静态文件(css,js,img)
*routes,存放路由文件
*views,存放前台页面文件
这些结构基本包含了上述提到的Web项目搭建的要素,但是目前类似express-generator的Koa部署工具Koa-generator(非官方)并不完善并且个人测试存在些许错误。其实Koa-generator也是仿造上述express-generator生成的目录,既然这样还不如手动创建目录来的爽快(generator-k是另一款生成器,用上去感觉还行),在根目录新建app.js作为程序的启动文件,创建三个文件夹分别命名public、routes和views,最后新建package.json文件存放你的项目的一些信息。完成这些创建之后,用npm命令安装Koa,这样的话一个基本的Koa框架就搭建好了,非常的的轻量级,它的目录结构如下:
```
|——app.js
|——node_modules
|——public
| |——img
| |——css
| |——js
|
|——routes
| |——index.js
| |——user.Js
|
|——views
| |——_layout.html
| |——index.html
|
|——package.json
Koa项目运行:node --harmony app.js
必须加 --harmony ,这样才会支持 ES6 语法。
```
**2、Koa日志**
日志是项目error调试和日常维护的基本手段,Koa有日志模块Koa-logger,npm install Koa-logger后使用app.use(logger());命令程序就会在控制台自动打印日志,当然如果你对Koa-logger的风格不满意或者想要看到更多得信息也可以自己编辑代码实现有自己风格的日志打印。
例如:
```
auto map route -> [get]/authority/saveAddUser/
auto map route -> [get]/authority/searchUserInfo/
auto map route -> [get]/authority/updateUser/
auto map route -> [get]/authority/deletedUser/
auto map route -> [get]/authority/getSelectValues/
auto map route -> [get]/authority/saveAuthority/
```
最后呢,如果有需要,要把日志进行存储。
**3、Koa的错误处理**
Koa 有 error 事件,当发生错误时,可以通过该事件,对错误进行统一的处理。
```
var Koa = require('koa');
var app = Koa();
app.on('error', function(err,ctx){
console.log(err);
});
app.listen(3000);
```
上面这段代码在如果捕获到错误,页面会打印出 “Internal Server Error” (这是Koa对错误的默认处理)。这个错误我们在综合监控系统中也经常见到,那么我们显然无法根据这条日志得到什么信息
```
TypeError: Cannot read property 'split' of undefined
at Object.Home.index (d:\test\route\home.js:143:31)
at GeneratorFunctionPrototype.next (native)
at Object.dispatch (d:\test\node_modules\koa-router\lib\router.js:97:44)
at GeneratorFunctionPrototype.next (native)
```
这些错误信息是怎么报出来的的呢,其实是Koa-onerror 中间件,它优化错误信息,根据这些错误信息就能更好的捕获到错误。
Koa-onerror使用方法:
```
var onerror = require('Koa-onerror');
onerror(app);
```
**4、Koa静态文件指定**
Koa静态文件指定中间件Koa-static,npm install Koa-static之后就可以使用Koa-static负责托管 Koa 应用内的静态资源。映射了静态文件目录,引用的时候直接去该目录下寻找资源,会减少一些消耗。(不知道讲的准确不准确,只是个人的理解)指定public为静态文件目录的代码如下:
```
var staticServer = require('koa-static');
var path = require('path');
app.use(staticServer(path.join(__dirname,'public')));
```
**5、ejs模板的使用**
渲染页面需要一种模板,这里选择风格接近html的ejs模板。npm install Koa-ejs后就可以在Koa框架中使用ejs模版。
```
var render = require('koa-ejs');
render(app, {
root: path.join(__dirname, 'views'),
layout: '__layout',
viewExt: 'html',
cache: false,
debug: true
});
app.use(function *(){
yield this.render('index',{layout:false});
});
```
**6、Koa路由设置**
Koa个极简的web框架,简单到连路由模块都没有配备。自己手写路由是这样的:
```
app.use(function *(){
//我是首页
if(this.path==='/'){
}
});
```
使用更加强大的路由中间件,Koa中设置路由一般安装Koa-router,Koa-router支持五种方法
```
router.get()
router.post()
router.put()
router.del()
router.patch()
```
GET方法举例:
```
var app = require('koa')();
var Router = require('koa-router');
var myRouter = new Router();
myRouter.get('/', function *(next) {
yield this.render('index',{layout:false});
});
app.use(myRouter.routes());
app.listen(3000);
```
Koa-router 拥有丰富的 api 细节,用好这些 api ,可以让页面代码更为优雅与可维护。
接收query参数
```
http://localhost:3000/?a=1(条件)
index.js
var router = require('koa-router')();
router
.get('/',function *(next){
console.log(this.query);
yield this.render('index',{layout:false});
})
.get('/home',function *(ctx,next){
ctx.render('home');
});
//ctx为Koa2.0中支持
... ...
module.exports = router;
控制台打印:
<-- GET /?a=1
{ a: '1' }
{ a: '1' }
接收params参数
http://localhost:3000/users/123(参数)
router.get('/user/:id', function *(next) {
console.log(this.params.id);
});
```
param() 用于封装参数处理中间件,当访问 /detail/:id 路由时,会先执行 param() 定义的 generator function 逻辑。函数的第一个是路由参数的值,next 是中间件流程关键标识变量。
yield next;
表示执行下一个中间件。
```
app.param('id',function *(id,next){
this.id = Number(id);
if ( typeof this.id != 'number') return this.status = 404;
yield next;
}).get('/detail/:id', function *(next) {
//我是详情页面
var id = this.id; //123
this.body = id;
});
```
**7、Koa中间件**
Koa的中间件很像Express的中间件,也是对HTTP请求进行处理的函数,但是必须是一个Generator函数即 function *(){} 语法,不然会报错。可以这么说,Nodejs的Web程序中任何请求和响应都是中间件在操作。
```
app
.use(logger()) //日志中间件
.use(serve(__dirname + '/public')) //静态文件指定中间件
.use(router.routes()) //路由中间件
.use(router.allowedMethods()); //路由中间件
```
app.use 加载用于处理http请求的middleware(中间件),当一个请求来的时候,会依次被这些 middlewares处理。执行的顺序是你定义的顺序。中间件的执行顺序规则是类似“栈”的结构,所有需要执行的中间件都被一个一个放入“栈”中,当没有遇到next()的时候,“栈”里边的这些中间件被逆序执行。
```
app.use(function *(next){
this; // is the Context
this.request; // is a Koa Request
this.response; // is a Koa Response
});
```
说明:
•this是上下文
*代表es6里的generator
http模型里的请求和响应
•this.request
•this.response
app.use() 究竟发生了什么不可思议的化学反应呢?
其实 app.use() 就干了一件事,就是将中间件放入一个数组,真正执行逻辑的是:app.listen(3000);
Koa 的 listen() 除了指定了 http 服务的端口号外,还会启动 http server,等价于:
```
var http = require('http');
http.createServer(app.callback()).listen(3000);
```
后面这种繁琐的形式有什么用呢?
一个典型的场景是启动 https 服务,默认 app.listen(); 是启动 http 服务,启动 https 服务就需要:
```
var https = require('https');
https.createServer(app.callback()).listen(3000);
```
### 二、异步编程
**1、异步流程控制**
异步编程对 JavaScript 语言太重要。JavaScript 只有一根线程,如果没有异步编程,根本没法用,非卡死不可。
以前,异步编程的方法,大概有下面四种。
回调函数
事件监听
发布/订阅
Promise 对象
JavaScript 语言对异步编程的实现,就是回调函数。所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数。它的英语名字 callback,直译过来就是"重新调用"。
读取文件进行处理,是这样写的。
```
fs.readFile('/etc/passwd', function (err, data) {
if (err) throw err;
console.log(data);
});
```
上面代码中,readFile 函数的第二个参数,就是回调函数,也就是任务的第二段。等到操作系统返回了 /etc/passwd 这个文件以后,回调函数才会执行。回调函数本身并没有问题,它的问题出现在多个回调函数嵌套。假定读取A文件之后,再读取B文件,代码如下。
```
fs.readFile(fileA, function (err, data) {
fs.readFile(fileB, function (err, data) {
// ...
});
});
```
不难想象,如果依次读取多个文件,就会出现多重嵌套。代码不是纵向发展,而是横向发展,很快就会乱成一团,无法管理。这种情况就称为"回调函数噩梦"(callback hell)。Promise就是为了解决这个问题而提出的。它不是新的语法功能,而是一种新的写法,允许将回调函数的横向加载,改成纵向加载。采用Promise,连续读取多个文件,写法如下。
```
var readFile = require('fs-readfile-promise');
readFile(fileA)
.then(function(data){
console.log(data.toString());
})
.then(function(){
return readFile(fileB);
})
.then(function(data){
console.log(data.toString());
})
.catch(function(err) {
console.log(err);
});
```
上面代码中,我使用了 fs-readfile-promise 模块,它的作用就是返回一个 Promise 版本的 readFile 函数。Promise 提供 then 方法加载回调函数,catch方法捕捉执行过程中抛出的错误。可以看到,Promise 的写法只是回调函数的改进,使用then方法以后,异步任务的两段执行看得更清楚了,除此以外,并无新意。
Promise 的最大问题是代码冗余,原来的任务被Promise 包装了一下,不管什么操作,一眼看去都是一堆 then,原来的语义变得很不清楚。
那么,有没有更好的写法呢?
ECMAScript 6 (简称 ES6 )作为下一代 JavaScript 语言,将 JavaScript 异步编程带入了一个全新的阶段。异步编程的语法目标,就是怎样让它更像同步编程。
Koa 的先天优势在于 generator。
generator指的是
```
function* xxx(){
}
```
是es6里的写法。
```
var r = 3;
function* infinite_ap(a) {
for( var i = 0; i < 3 ; i++) {
a = a + r ;
yield a;
}
}
var sum = infinite_ap(5);
console.log(sum.next()); // returns { value : 8, done : false }
console.log(sum.next()); // returns { value : 11, done: false }
console.log(sum.next()); // returns { value : 14, done: false }
console.log(sum.next()); //return { value: undefined, done: true }
```
yield语句就是暂停标志,next方法遇到yield,就会暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回对象的value属性的值。当下一次调用next方法时,再继续往下执行,直到遇到下一个yield语句。如果没有再遇到新的yield语句,就一直运行到函数结束,将return语句后面的表达式的值,作为value属性的值,如果该函数没有return语句,则value属性的值为undefined。当第一次调用 sum.next() 时 返回的a变量值是5 + 3,同理第二次调用 sum.next() ,a变量值是8 +3,知道循环执行结束,返回done:true标识。大家有没有发现个问题,Koa 中 generator 的用法与上述 demo 演示的用法有非常大得差异,那是因为 Koa 中的 generator 使用了 co 进行了封装。
**2、co的使用**
Ps:(这里只是简单介绍,后续可以作为一个专题来讲)
co 函数库是著名程序员 TJ Holowaychuk 于2013年6月发布的一个小工具,用于 Generator 函数的自动执行。
比如,有一个 Generator 函数,用于依次读取两个文件。
```
var gen = function* (){
var f1 = yield readFile('/etc/fstab');
var f2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
```
co 函数库可以让你不用编写 Generator 函数的执行器。
```
var co = require('co');
co(gen);
```
上面代码中,Generator 函数只要传入 co 函数,就会自动执行。
co 函数返回一个 Promise 对象,因此可以用 then 方法添加回调函数。
```
co(gen).then(function (){
console.log('Generator 函数执行完成');
})
```
上面代码中,等到 Generator 函数执行结束,就会输出一行提示。
为什么 co 可以自动执行 Generator 函数?
前面文章说过,Generator 函数就是一个异步操作的容器。它的自动执行需要一种机制,当异步操作有了结果,能够自动交回执行权。
两种方法可以做到这一点。
(1)回调函数。将异步操作包装成 Thunk 函数,在回调函数里面交回执行权。
(2)Promise 对象。将异步操作包装成 Promise 对象,用 then 方法交回执行权。
co 函数库其实就是将两种自动执行器(Thunk 函数和 Promise 对象),包装成一个库。使用 co 的前提条件是,Generator 函数的 yield 命令后面,只能是 Thunk 函数或 Promise 对象。
参考:[http://www.ruanyifeng.com/blog/2015/05/co.html](http://www.ruanyifeng.com/blog/2015/05/co.html)
**3、Koa 中间件机制实现原理**
使用 Koa 的同学一定会有如下疑问:
1. Koa 的中间件机制是如何实现?
2. 为什么中间件必须是 generator function?
3. next 实参指向是什么?为什么可以通过 yield next 可以执行下一个中间件?
4. 为什么中间件从上到下执行完后,可以从下到上执行 yield next 后的逻辑?
通过实现简单的 Koa 框架(剥离除中间件外所有的逻辑)来解答上述问题,这个框架的名字叫 SimpleKoa:
```
var co = require('co');
function SimpleKoa(){
this.middlewares = [];
}
SimpleKoa.prototype = {
//注入个中间件
use: function(gf){
this.middlewares.push(gf);
},
//执行中间件
listen: function(){
this._run();
},
_run: function(){
var ctx = this;
var middlewares = ctx.middlewares;
return co(function *(){
var prev = null;
var i = middlewares.length;
//从最后一个中间件到第一个中间件的顺序开始遍历
while (i--) {
//实际Koa的ctx应该指向server的上下文,这里做了简化
//prev 将前面一个中间件传递给当前中间件
prev = middlewares[i].call(ctx, prev);
}
//执行第一个中间件
yield prev;
})();
}
};
```
写个 demo 印证下中间件执行顺序:
```
var app = new SimpleKoa();
app.use(function *(next){
this.body = '1';
yield next;
this.body += '5';
console.log(this.body);
});
app.use(function *(next){
this.body += '2';
yield next;
this.body += '4';
});
app.use(function *(next){
this.body += '3';
});
app.listen();
```
执行后控制台输出:123456,对照 Koa 中间件执行顺序,完全一致!寥寥几行代码,我们就实现了 Koa 的中间件机制!这就是 co 的魔力。
### 三、Koa中涉及但本次没有讲的问题
**1、Koa中的cookie和session(后续详细讲解)**
web应用程序都离不开cookie和session的使用,是因为Http是一种无状态性的协议。保存用户状态信息的一种方法或手段,Session 与 Cookie 的作用都是为了保持访问用户与后端服务器的交互状态。
**2、Koa中nosql(后续技术分享会详细讲解)**
mongodb是一个基于文档的非关系型数据库,所有数据是从磁盘上进行读写的,其优势在于查询功能比较强大,能存储海量数据。
redis是内存型数据库,数据保存在内存中,通过tcp直接存取,优势是速度快,并发高,缺点是数据类型有限,查询功能不强,一般用作缓存。它由C语言实现的,与 NodeJS工作原理近似,同样以单线程异步的方式工作,先读写内存再异步同步到磁盘,读写速度上比MongoDB有巨大的提升,当并发达到一定程度时,即可考虑使用Redis来缓存数据和持久化Session。
```
var mongoose = require('mongoose');
// 引入 mongoose 模块
mongoose.connect('mongodb://localhost/blog');
// 然后连接对应的数据库:mongodb://localhost/test
// 其中,前面那个 mongodb 是 protocol scheme 的名称;localhost 是 mongod 所在的地址;
// 端口号省略则默认连接 27017;blog是数据库的名称
// mongodb 中不需要建立数据库,当你需要连接的数据库不存在时,会自动创建一个出来。
module.exports = mongoose;
// 导出 mongoose 模块
var mongoose = require('../modules/db');
// 引入 mongoose 模块
var User = mongoose.model('User',{
name: {type: String, match: /^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/},
password: String
});
//创建了一个名为 User 的 model
var user1 = new User({name:'12345@qqqqqq.com'});
user1.password = 'a5201314';
user1.save(function(err){
if(err){
console.log("save error");
}
});
```
\ No newline at end of file
Create a new repository on the command line
touch README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin https://github.com/a1511870876/secondWorks.git
git push -u origin master
Push an existing repository from the command line
git remote add origin https://github.com/a1511870876/secondWorks.git
git push -u origin master
\ No newline at end of file
### 主要是自己使用mongoose的一些有疑虑的地方简单介绍
初次使用mongoose的过程中有很多的疑惑,MongoDB是文档型数据库,文档保存在集合中,所有的增删改查都是在集合中操作,而在mongoose中很多操作并没有集合的概念,因此在集合的创建、查询、删除等等操作的时候,我就会想Collections在哪?相信初学者都会有这样的疑惑。直到翻看了官方文档中的一句话,“With Mongoose, everything is derived from a Schema.”注意,是everything。记住这句话,我相信不管是学习还是使用mongoose,那么思考的方向已经对了。
使用mongoose连接MongoDB就不多说了,直接上代码:
var mongoose = require(‘mongoose’);
// 引入 mongoose 模块
mongoose.connect(‘mongodb://localhost/test);
// 然后连接对应的数据库:mongodb://localhost/test
// 其中,前面那个 mongodb 是 protocol scheme 的名称;localhost 是 mongod 所在的地址;
// 端口号省略则默认连接 27017;test 是数据库的名称
// mongodb 中不需要建立数据库,当你需要连接的数据库不存在时,会自动创建一个出来。
var db = mongoose.connection;
db.on(‘error’, console.error.bind(console, ‘connection error:’));
db.once(‘open’, function (callback) {
console.log(“MongoDB Opened!”);
});
module.exports = mongoose;
值得注意的是,考虑任何问题,尤其是我们码农在程序中考虑任何问题,都要考虑发生错误怎么办,使用mongoose也不例外。
var mongoose = require(’…/modules/db’);
var impressionSchema = mongoose.Schema({
impression:{type:String},
author:{type:String}
});
var impressionModel = mongoose.model(‘friendimpression’,impressionSchema);
var impression = new impressionModel({impression:“fool”,author:“sweety”});
impression.save(function (err) {
if (err) return console.error(err);
console.log(“Save Successful!”);
});
这段代码是保存一个文档的实例,在这段代码中我的疑虑是我们把文档保存在哪个Collection里边?答案仍然是“With Mongoose, everything is derived from a Schema.”,mongoose是通过model来创建mongodb中对应的collection的,mongoose在内部创建collection时将我们传递的collection名(‘friendimpression’)小写化,同时如果小写化的名称后面没有字母——s,则会在其后面添加一s,针对我们刚建的collection,则会命名为:friendimpressions。
impressionModel.find(function (err, docs) {
if (err) return console.error(err);
console.log(docs)
});
};
查询的疑虑在于,我如果对存在的表进行查询怎么办?我必须先创建model?可是我不需要插入删除等操作,我只想查询一下就完事儿。看一下mongoose官方的查询方法Model.find、Model.findOne、Model.findById、Model.where、Model.$where等等,都是基于Model,Model又来自Schema,其实Schema就是你文档结构的规则,俗话说无规矩不成方圆,MongoDB也是一样,不关你是查询还是插入、删除都得有个规矩,所以即使是简单的查询也要从Schema开始,有了规矩增删改查起来也方便很多。
\ No newline at end of file
### 功能
每天定时截图,并把截到的图片自动通过邮件发送。
### 说明
代码注释已经非常详细,就不多做说明,需要的朋友自己查看代码即可,主文件Mail.js,截图文件capturePart1.js,capturePart2.js,capturePart3.js,这里只展示了capturePart1.js其他两个类似。值得注意的是有登录权限的网站一定要设置Cookie,需要截取高质量图片的话截取时间一定设置长一些。
### Mail.js
```
* 定时发送邮件功能说明:
* node.js必备安装模块:node_modules-->phantomjs,nodemailer,node-schedule,moment
* 涉及JS文件:route-->mail.js,public-->js-->capturePart1.js,capturePart2.js,capturePart3.js
* 截图保存地址:public-->images-->mainPage.jpeg(1600*4200)
* 截图url:http://www.***********.com
* 程序主要思路:
* (1)phantomjs截图-->参照http://phantomjs.org/
* (2)nodemailer发送邮件-->参照https://www.npmjs.com/package/nodemailer
* (3)node-schedule定时-->参照https://www.npmjs.com/package/node-schedule
* 注意:
* 改变发件服务器请修改SMTP
* 改变收件人请修改变量receiver
* 改变邮件内容请修改变量html
* 改变邮件附加图片和附件请修改attachments
* 改变截图功能请修改public-->js-->server.js
* 改变定时功能请修改变量rule
* ------Sweety
```
//组件引入开始
var schedule = require("node-schedule");
var path = require('path');
var childProcess = require('child_process');
var phantomjs = require('phantomjs');
var nodemailer = require("nodemailer");
var moment = require("moment");
```
//组件引入结束
/*--------------------------------------------------------------------------------------------------------------------------------------------*/
//变量定义开始
var today; //今天开始时间
var binPath = phantomjs.path; //获取phantomjs.exe路径
var jsPath = process.cwd()+"/public/js/"; //获取server.js所在目录
var childArgs;
//capturePart3();
//capturePart1();
//变量定义结束
/*--------------------------------------------------------------------------------------------------------------------------------------------*/
//主程序开始
var rule = new schedule.RecurrenceRule(); //schedule定时器
rule.hour = 11;
rule.minute = 0;
rule.second = 0; //定时器规则设定(每天11点触发事件)
var j = schedule.scheduleJob(rule, function(){
var now = moment();
today = now.clone().add(-1, 'days').format('YYYY-MM-DD');
capturePart1(); //触发截图事件(邮件发送功能包含在截图事件里边)
});
//主程序结束
/*---------------------------------------------------------------------------------------------------------------------------------------------*/
//phantomjs截图开始(第一张)
function capturePart1(){
childArgs = [
path.join(jsPath, 'serverPart1.js'), //server.js
' https://www.hao123.com ' //要截图的url
];
childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) {
if(err)
{
console.log(err); //打印错误信息
}else{
console.log("Captured Part1 Successful !!"); //打印正确信息
capturePart2();
}
});
}
//phantomjs截图结束(第一张)
//phantomjs截图开始(第二张)
function capturePart2(){
childArgs = [
path.join(jsPath, 'serverPart2.js'), //server.js路径
'https://www.hao123.com ' //要截图的url
];
childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) {
if(err)
{
console.log(err); //打印错误信息
}else{
console.log("Captured Part2 Successful !!"); //打印正确信息
capturePart3();
}
});
}
//phantomjs截图结束(第二张)
//phantomjs截图开始(第三张)
function capturePart3(){
childArgs = [
path.join(jsPath, 'serverPart3.js'), //server.js路径
' https://www.hao123.com ' //要截图的url
];
childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) {
if(err)
{
console.log(err); //打印错误信息
}else{
console.log("Captured Part3 Successful !!"); //打印正确信息
sent(); // 触发发送邮件事件
}
});
}
//phantomjs截图结束(第三张)
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
//nodemailer发送邮件开始
function sent(){
var imgPart1 = fs.readFileSync(process.cwd()+"/public/images/mainPagePart1.jpeg"); //图片来源
var imgPart2 = fs.readFileSync(process.cwd()+"/public/images/mainPagePart2.jpeg"); //图片来源
var imgPart3 = fs.readFileSync(process.cwd()+"/public/images/mainPagePart3.jpeg"); //图片来源
var smtpTransport = nodemailer.createTransport("SMTP",{ //邮件SMTP设定(发送邮箱服务器必须开启SMTP)
host: "smtp.xxxxx.com", // 主机
secureConnection: false, // 不使用 SSL
port: 587, // SMTP 端口
auth: {
user: "xxxxx@xxxx.com", //用户名
pass: "xxxxxx" //密码
}
});
var html = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' +
'XX好:</br>'+
'&nbsp;&nbsp;下面为【XXXX】日报汇报('+today+')的内容,请参考</br>' +
'&nbsp;&nbsp;(日报详细信息请点击<a href="#" onclick="changeData();">此处登陆</a>查看)'+
'</br>' +
'<img src="cid:img1" id="img1">'+
'<img src="cid:img2" id="img2">'+
'<img src="cid:img3" id="img3">';//邮件内容(html代码),img唯一指定地址对应cid(见mailOptions设定)
var receiver = "xxx@xxx.com";//收件人列表
var cc = "xxxx@xxxx.com,xxx@xxx.com,xxx@xxxx.com"; //抄送人列表
var bcc = "xxx@xxxx.com,xxx@xxxx.com"; //密抄送人列表
var mailOptions = { //邮件内容选项设定
from: "<xxx@xxxx.com>", //发件地址
//to: "xxx@xxxx.com",
to: receiver, //收件人
cc:cc, //抄送人
bcc:bcc, //密抄送人
subject:"【XXXX】日报汇报("+today+")", //邮件主题
text: "【XXXX】日报汇报("+today+")", // plaintext body
html:html, //html内容
attachments: [
{
filename: 'mainPagePart1.jpeg', //图片名称
contents: imgPart1, //图片来源
cid: 'img1' //插入图片标识
},{
filename: 'mainPagePart2.jpeg', //图片名称
contents: imgPart2, //图片来源
cid: 'img2' //插入图片标识
},{
filename: 'mainPagePart3.jpeg', //图片名称
contents: imgPart3, //图片来源
cid: 'img3' //插入图片标识
}
]
};
smtpTransport.sendMail(mailOptions, function(error, response){//发送邮件
if(error){
console.log(error); //打印错误信息
}else{
console.log("Sent Successful !!"); //打印正确信息
}
});
}
//nodemailer发送邮件结束
function changeData(){
}
/*---------------------------------------------------------------------------------------------------------------------------------------------*/
```
### capturePart1.js
```
//phantomjs截图
var page = require('webpage').create(),
system = require('system'),
address;
page.viewportSize = { width:1920, height: 1080};
page.clipRect = { top: 200, left: 210, width: 1680, height: 1530 };
page.customHeaders={"Cookie":"koa:sess=e*******=;koa:sess.sig=pjadZtLAVtiO6-Haw1vnZZWrRm8"};
if (system.args.length === 1) {
phantom.exit(1);
} else {
address = system.args[1];
page.open(address, function (status) {
});
}
setTimeout(function() {
console.log("");
console.log("### STEP 5: Close page and shutdown (with a delay)");
page.render('./public/images/mainPagePart1.jpeg', {format: 'jpeg', quality: '100'});
page.close();
setTimeout(function(){
phantom.exit();
}, 3000);
}, 19000);
```
\ No newline at end of file
## Package管理
后台npm
(不多说)
前台bower
简介:
Bower的功能类似于Nodejs中的npm或者Python中的pip,用于web包管理,如果越来越多得开源项目都托管在github上,bower只需要将github上项目加上一个配置文件既可以使用bower方式使用安装包。作为包管理,bower能提供添加新web包,更新web包,删除web包,发布web包功能,管理包依赖。web包通常认为由html+css+javascript构成。使用:
根据上面的简介描述,bower依赖于nodejs,下载安装依赖库实际上是使用git进行下载,因此使用bower前确保安装了Node和Git环境,并且建议使用git bash命令行来执行bower install命令。
(常用npm、node、大神略过此段)另外可能我们需要在任何目录使用bower命令的话,需要配置npm环境变量,这一步很重要,不然会提示“bower”不是内部或外部命令,配置npm环境变量就很简单了,在path目录下添加npm全局的包的安装路径但不包含node_modules目录,另外新建NODE_PATH,值为全局的包的安装路径包含node_modules目录,例如:path:D:\node,NODE_PATH:D:\node\node_modules,这样我们npm install XXX –g的安装包才能在全局使用,不会出现提示“XXX不是内部或外部命令”。
好了,废话不多说,bower使用就很简单了:
安装bower
npm install bower -g
在项目目录中运行
bower install jquery
运行成功之后项目中会多出components文件夹,文件夹中jquery文件夹,jquery文件夹里面就有最新的jquery文件。
这还不能说明他NB的地方,试想下面的场景,jQuery升级了,是不是再down一次jQuery呢?bower可以这样做:
bower update jquery
就可以自动升级到最新版的jquery了。
再假设我们需要使用bootstrap,bootstrap可不是一个文件,有css,js还有图片。js还依赖于jQuery,如果使用bower:
bower install bootstrap
bower会自动从github上down最新的代码,而且,会自动将依赖包jquery也down一次。
如果你发布程序的时候不想把一些依赖的库发布上去(主要原因是太大了 – – ),可以在项目根目录下生成一个 bower.json 文件用来管理依赖。
在项目目录下执行
bower init
按照提示操作就好,这样子会生成一个bower文件
安装 jquery
bower install jquery --save
这样子 bower.json 文件就会写入一个 Jquery的依赖项
别人只要在项目目录下输入
bower install
就会自动安装了
## 正则表达式学习
.就是一个占位符,匹配除'\n'之外的任意字符。
*匹配前面字符0次或任意次
?匹配前一个字符0次或1次
-----------------------------------------------------------------
上面的内容全部只需要了解即可,需要掌握的只有下面这一种组合方式(.*?)
.* 贪心算法,尽可能多的匹配,像一个胖子尽可能多的吃
.*?非贪心算法,尽可能少的匹配,像一个婴儿少量多餐
例如:code = 'hhosahfoxxIxxohofhjosfhxxlovexxoruowhntlnmlxxyouxxljh'
re.findall('xx.*xx',code)匹配第一个xx到最后一个xx,即xxIxxohofhjosfhxxlovexxoruowhntlnmlxxyouxx
re.findall('xx.*?xx',code)匹配结果['xxIxx','xxlovexx','xxyouxx']
(.*?)括号内的数据作为结果返回
例如:d = re.findall('xx(.*?)xx',code)
for each in d
print each
打印结果:
I
love
you
-----------------------------------------------------------------
re.S
例如:code = 'hhosahfoxxI
xxohofhjosfhxxlovexxoruowhntlnmlxxyouxxljh'
d = re.findall('xx(.*?)xx',code)
print d
打印结果['ohofhjosfh','oruowhntlnml']
解释:.号可以匹配任意字符,但除了换行符'\n'
这时候就需要re.S
例如:d = re.findall('xx(.*?)xx',code,re.S)
print d
打印结果['I\n','love','you']
可以看出re.S的作用使.包括\n
其他:
重点掌握三个
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
-----------------------------------------------------------------
对比findall与search的区别
s2 = 'asdfxxIxx123xxlovexxdfdasdfxxIxx123xxlovexxdfd'
f = re.search('xx(.*?)xx123xx(.*?)xx',s2)
print f.group(2)
if not f:
print 'not'
else:
print 'yes'
输出结果:
love
yes
注:re.serch与re.match()区别是re.match()只匹配字符串的开始,则匹配失败,函数返回None
f2 = re.findall('xx(.*?)xx123xx(.*?)xx',s2)
print f2
输出结果:
[('I', 'love'), ('I', 'love')]
注:findall返回一个list,有多次匹配在list中嵌套tuple(元组)
-----------------------------------------------------------------
sub的使用
s = '123abccssfadjfdj123'
output = re.sub('123(.*?)123','123%d123%789',s)
print output
-----------------------------------------------------------------
常用技巧
1、在确定只有一个内容时,使用search方法可以提高效率
2、不要要使用compile
str = 'asdfxxIxx123xxlovexxdfdasdfxxIxx123xxlovexxdfd'
pattern = 'xx(.*?)xx'
new_pattern = re.compile(pattern,re.S)
output = re.findall(new_pattern,str)
3、匹配数字使用\d+
a = 'asdsds123456fasd888fas'
b = re.findall('(\d+)',a)
print b
执行结果:['123456','888']
-----------------------------------------------------------------
总结
re.match 尝试从字符串的起始位置匹配一个模式。
re.search 扫描整个字符串并返回第一个成功的匹配。
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
re.sub用于替换字符串中的匹配项。
re.split按照能够匹配的子串将string分割后返回列表。
re.findall搜索string,以列表形式返回全部能匹配的子串。
re.finditer搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
. 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
\d 匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
\W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。
[Pp]ython 匹配 "Python" 或 "python"
rub[ye] 匹配 "ruby" 或 "rube"
[aeiou] 匹配中括号内的任意一个字母
[0-9] 匹配任何数字。类似于 [0123456789]
[a-z] 匹配任何小写字母
[A-Z] 匹配任何大写字母
[a-zA-Z0-9] 匹配任何字母及数字
[^aeiou] 除了aeiou字母以外的所有字符
[^0-9] 匹配除了数字外的字符
. 点 匹配单个任意字符
[...] 字符组 匹配单个字符组出现的字符
[^...] 排除型字符组 匹配单个未在字符组出现的字符
\char 转义符 如果char是元字符或没有特殊含义, 则匹配char。
? 问号 容许非必须的一次匹配
+ 加号 匹配1次以上
* 星号 匹配任意次
{min,max} 区间量词 匹配min次到max次。
^$ 脱字符和美元符 匹配一行文本的开头和结束。
\b 边界符 匹配单词的边界
| | 多选结构
(...) 括号 用处有三,请看上面
\1.\2 反向引用 对括号捕捉到的分组进行引用。
括号
如果需要使用分组,或者对一个分组进行量词限定,就可以使用它了。使用括号以后,可以:
在后面进行反向引用
作为一个子表达式使用
限制多选结构
-----------------------------------------------------------------
\ No newline at end of file
### 功能
每天定时截图,并把截到的图片自动通过邮件发送。
### 说明
代码注释已经非常详细,就不多做说明,需要的朋友自己查看代码即可,主文件Mail.js,截图文件capturePart1.js,capturePart2.js,capturePart3.js,这里只展示了capturePart1.js其他两个类似。值得注意的是有登录权限的网站一定要设置Cookie,需要截取高质量图片的话截取时间一定设置长一些。
### Mail.js
```
/************************************************************************************************************
* 定时发送邮件功能说明:
* node.js必备安装模块:node_modules-->phantomjs,nodemailer,node-schedule,moment
* 涉及JS文件:route-->mail.js,public-->js-->capturePart1.js,capturePart2.js,capturePart3.js
* 截图保存地址:public-->images-->mainPage.jpeg(1600*4200)
* 截图url:http://www.***********.com
* 程序主要思路:
* (1)phantomjs截图-->参照http://phantomjs.org/
* (2)nodemailer发送邮件-->参照https://www.npmjs.com/package/nodemailer
* (3)node-schedule定时-->参照https://www.npmjs.com/package/node-schedule
* 注意:
* 改变发件服务器请修改SMTP
* 改变收件人请修改变量receiver
* 改变邮件内容请修改变量html
* 改变邮件附加图片和附件请修改attachments
* 改变截图功能请修改public-->js-->server.js
* 改变定时功能请修改变量rule
* ------Sweety
***************************************************************************************************************/
//组件引入开始
var schedule = require("node-schedule");
var path = require('path');
var childProcess = require('child_process');
var phantomjs = require('phantomjs');
var nodemailer = require("nodemailer");
var moment = require("moment");
//组件引入结束
/*--------------------------------------------------------------------------------------------------------------------------------------------*/
//变量定义开始
var today; //今天开始时间
var binPath = phantomjs.path; //获取phantomjs.exe路径
var jsPath = process.cwd()+"/public/js/"; //获取server.js所在目录
var childArgs;
//capturePart3();
//capturePart1();
//变量定义结束
/*--------------------------------------------------------------------------------------------------------------------------------------------*/
//主程序开始
var rule = new schedule.RecurrenceRule(); //schedule定时器
rule.hour = 11;
rule.minute = 0;
rule.second = 0; //定时器规则设定(每天11点触发事件)
var j = schedule.scheduleJob(rule, function(){
var now = moment();
today = now.clone().add(-1, 'days').format('YYYY-MM-DD');
capturePart1(); //触发截图事件(邮件发送功能包含在截图事件里边)
});
//主程序结束
/*---------------------------------------------------------------------------------------------------------------------------------------------*/
//phantomjs截图开始(第一张)
function capturePart1(){
childArgs = [
path.join(jsPath, 'serverPart1.js'), //server.js
' https://www.hao123.com ' //要截图的url
];
childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) {
if(err)
{
console.log(err); //打印错误信息
}else{
console.log("Captured Part1 Successful !!"); //打印正确信息
capturePart2();
}
});
}
//phantomjs截图结束(第一张)
//phantomjs截图开始(第二张)
function capturePart2(){
childArgs = [
path.join(jsPath, 'serverPart2.js'), //server.js路径
'https://www.hao123.com ' //要截图的url
];
childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) {
if(err)
{
console.log(err); //打印错误信息
}else{
console.log("Captured Part2 Successful !!"); //打印正确信息
capturePart3();
}
});
}
//phantomjs截图结束(第二张)
//phantomjs截图开始(第三张)
function capturePart3(){
childArgs = [
path.join(jsPath, 'serverPart3.js'), //server.js路径
' https://www.hao123.com ' //要截图的url
];
childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) {
if(err)
{
console.log(err); //打印错误信息
}else{
console.log("Captured Part3 Successful !!"); //打印正确信息
sent(); // 触发发送邮件事件
}
});
}
//phantomjs截图结束(第三张)
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
//nodemailer发送邮件开始
function sent(){
var imgPart1 = fs.readFileSync(process.cwd()+"/public/images/mainPagePart1.jpeg"); //图片来源
var imgPart2 = fs.readFileSync(process.cwd()+"/public/images/mainPagePart2.jpeg"); //图片来源
var imgPart3 = fs.readFileSync(process.cwd()+"/public/images/mainPagePart3.jpeg"); //图片来源
var smtpTransport = nodemailer.createTransport("SMTP",{ //邮件SMTP设定(发送邮箱服务器必须开启SMTP)
host: "smtp.xxxxx.com", // 主机
secureConnection: false, // 不使用 SSL
port: 587, // SMTP 端口
auth: {
user: "xxxxx@xxxx.com", //用户名
pass: "xxxxxx" //密码
}
});
var html = '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' +
'XX好:</br>'+
'&nbsp;&nbsp;下面为【XXXX】日报汇报('+today+')的内容,请参考</br>' +
'&nbsp;&nbsp;(日报详细信息请点击<a href="#" onclick="changeData();">此处登陆</a>查看)'+
'</br>' +
'<img src="cid:img1" id="img1">'+
'<img src="cid:img2" id="img2">'+
'<img src="cid:img3" id="img3">';//邮件内容(html代码),img唯一指定地址对应cid(见mailOptions设定)
var receiver = "xxx@xxx.com";//收件人列表
var cc = "xxxx@xxxx.com,xxx@xxx.com,xxx@xxxx.com"; //抄送人列表
var bcc = "xxx@xxxx.com,xxx@xxxx.com"; //密抄送人列表
var mailOptions = { //邮件内容选项设定
from: "<xxx@xxxx.com>", //发件地址
//to: "xxx@xxxx.com",
to: receiver, //收件人
cc:cc, //抄送人
bcc:bcc, //密抄送人
subject:"【XXXX】日报汇报("+today+")", //邮件主题
text: "【XXXX】日报汇报("+today+")", // plaintext body
html:html, //html内容
attachments: [
{
filename: 'mainPagePart1.jpeg', //图片名称
contents: imgPart1, //图片来源
cid: 'img1' //插入图片标识
},{
filename: 'mainPagePart2.jpeg', //图片名称
contents: imgPart2, //图片来源
cid: 'img2' //插入图片标识
},{
filename: 'mainPagePart3.jpeg', //图片名称
contents: imgPart3, //图片来源
cid: 'img3' //插入图片标识
}
]
};
smtpTransport.sendMail(mailOptions, function(error, response){//发送邮件
if(error){
console.log(error); //打印错误信息
}else{
console.log("Sent Successful !!"); //打印正确信息
}
});
}
//nodemailer发送邮件结束
function changeData(){
}
/*---------------------------------------------------------------------------------------------------------------------------------------------*/
```
### capturePart1.js
```
//phantomjs截图
var page = require('webpage').create(),
system = require('system'),
address;
page.viewportSize = { width:1920, height: 1080};
page.clipRect = { top: 200, left: 210, width: 1680, height: 1530 };
page.customHeaders={"Cookie":"koa:sess=e*******=;koa:sess.sig=pjadZtLAVtiO6-Haw1vnZZWrRm8"};
if (system.args.length === 1) {
phantom.exit(1);
} else {
address = system.args[1];
page.open(address, function (status) {
});
}
setTimeout(function() {
console.log("");
console.log("### STEP 5: Close page and shutdown (with a delay)");
page.render('./public/images/mainPagePart1.jpeg', {format: 'jpeg', quality: '100'});
page.close();
setTimeout(function(){
phantom.exit();
}, 3000);
}, 19000);
```
\ No newline at end of file
## 重学JS
1、'use strict';
在strict模式下运行的JavaScript代码,强制通过var申明变量,未使用var申明变量就使用的,将导致运行错误。
2、字符串
toUpperCase()把一个字符串全部变为大写;
toLowerCase()把字符串全部变为小写;
indexOf()会搜索指定字符串第一次出现的位置,并返回下标,没找到返回-1;
substring(0,5);回指定索引区间的子串;
3、数组
arr.length;取得数组的长度,请注意,直接给Array的length赋一个新的值会导致Array大小的变化:
Array可以通过索引把对应的元素修改为新的值,请注意,如果通过索引赋值时,索引超过了范围,同样会引起Array大小的变化。
indexOf()用法类似字符串。
slice()就是对应String的substring()版本,它截取Array的部分元素,然后返回一个新的Array,只传递一个参数,会截取该参数到数组末尾的所有元素,不传递参数截取全部元素===复制数组。
\ No newline at end of file
## Html
1、<q></q>短文本引用,自动加双引号,语义是引用。
2、<blockquote></blockquote>长文本引用,自动两端缩进。
3、<br><br />为换行,&nbsp;为空格,<hr />为水平横线。
4、<address></address>地址。
5、<code></code>当代码为一行代码时,你就可以使用<code>标签了。
6、<pre></pre>语言代码段,多行。
7、<table summary="表格简介文本"><caption>标题文本</caption>
8、<a href="目标网址" target="_blank">click here!</a>新建浏览器窗口中打开链接。
9、<a href=”mailto: yy@qq.com?cc=xx@qq.com&bcc=zz@qq.com&subject=主题&body=内容”>发送</a>
(第一个参数用?隔开后边参数用&隔开,cc:抄送。Bcc:密抄送。Subject:标题。Body:内容)
10、<img src= alt= title= > src为图片地址;alt为下载不成功时描述性文本;title为图像可见时图像的描述。
11、<form method="传送方式" action="服务器文件">
12、<textarea rows="行数" cols="列数">文本</textarea>文本域。
13、<input type="radio/checkbox" value="值" name="名称" checked="checked"/>单选框、复选框。同一组的单选按钮,name 取值一定要一致,这样同一组的单选按钮才可以起到单选的作用。
14、<select><option value=”向服务器提交的值” selected=”selected”>显示的值</option></select>下拉框。multiple="multiple"使用下拉列表框进行多选。
15、<input type="submit" value="确定" />按钮,<input type="reset" value="重置" />重置按钮。
16、<label for="控件id名称">当用户单击选中该label标签时,浏览器就会自动将焦点转到和标签相关的表单控件上。
注意:标签的 for 属性中的值应当与相关控件的 id 属性值一定要相同。
## CSS
1、>作用于元素的第一代后代,空格作用于元素的所有后代。>适合包含样式时仅设置第一代后代样式。
2、伪类选择符a:hover{color:red;}鼠标滑过的状态。
3、有些特殊的情况需要为某些样式设置具有最高权值,怎么办?这时候我们可以使用!important来解决。
p{color:red!important;}
p{color:green;}
4、文字排版
字体p{font-family:"Microsoft Yahei";}现在一般网页喜欢设置“微软雅黑”
文字粗体p{font-weight:bold;}
文字斜体p{font-style:italic;}
文字下划线p{text-decoration:underline;}
文字删除线p{text-decoration:line-through;}
文字缩进p{text-indent:2em;} 2em的意思就是文字的2倍大小。
文字行间距p{line-height:1.5em;}
中文间距h1{letter-spacing:50px;} 字母间距h1{word-spacing:50px;}
5、段落排版
对齐h1{text-align:center;} {text-align:left;} {text-align:right;}
6、元素分类
常用的块状元素有:
<div><p><h1>...<h6><ol><ul><dl><table><address><blockquote><form>
常用的内联元素有:
<a><span><br><i><em><strong><label><q><var><cite><code>
常用的内联块状元素有:
<img><input>
7、元素分类--块级元素
每个块级元素都从新的一行开始,并且其后的元素也另起一行。
元素的高度、宽度、行高以及顶和底边距都可设置。
元素宽度在不设置的情况下,是它本身父容器的100%(和父元素的宽度一致),除非设定一个宽度。
将内联元素a转换为块状元素a{display:block;}
8、元素分类--内联元素
和其他元素都在一行上;
元素的高度、宽度及顶部和底部边距不可设置;
元素的宽度就是它包含的文字或图片的宽度,不可改变。
将块状元素设置为内联元素
div{display:inline;}
9、元素分类--内联块状元素
就是同时具备内联元素、块状元素的特点,代码display:inline-block就是将元素设置为内联块状元素。
10、盒子模型—块级标签
盒子和内容间隙叫padding,内边距,有四个方向top,right,bottom,left
盒子和盒子之间得间隙叫margin,外边距,有四个方向top,right,bottom,left
边框border有四个方向top,right,bottom,left
border-style(边框样式)常见样式有:dashed(虚线)| dotted(点线)| solid(实线)。
border-color(边框颜色)中的颜色可设置为十六进制颜色,如:border-color:#888;//前面的井号不要忘掉。
border-width(边框宽度)中的宽度也可以设置为:thin | medium | thick(但不是很常用),最常还是用象素(px)。
简写div{border:2px solid red;}
11、CSS布局模型
布局模型与盒模型一样都是 CSS 最基本、 最核心的概念。
在网页中,元素有三种布局模型:
1)流动模型(Flow)
2)浮动模型 (Float)
3)层模型(Layer)
CSS定义了一组定位(positioning)属性来支持层布局模型。
层模型有三种形式:
1)绝对定位(position: absolute)
2)相对定位(position: relative)
3)固定定位(position: fixed)
绝对定位,相对于父对象真实移动,如果没有父对象,父对象是body
.a{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}
相对定位,相对于该元素原始位置便宜,且偏移前的位置还保留不动,覆盖不了前面的div没有偏移前的位置。
固定定位,fixed:表示固定定位,与absolute定位类型类似,但它的相对移动的坐标是视图(屏幕内的网页窗口)本身。不会受文档流动影响。比如固定当前窗口的小广告
12、盒模型简写
margin:10px 15px 12px 14px;/*上设置为10px、右设置为15px、下设置为12px、左设置为14px*/
1、如果top、right、bottom、left的值相同,如下面代码:
margin:10px 10px 10px 10px;
可缩写为:
margin:10px;
2、如果top和bottom值相同、left和 right的值相同,如下面代码:
margin:10px 20px 10px 20px;
可缩写为:
margin:10px 20px;
3、如果left和right的值相同,如下面代码:
margin:10px 20px 30px 20px;
可缩写为:
margin:10px 20px 30px;
注意:padding、border的缩写方法和margin是一致的。
13、字体缩写
body{
font-style:italic;
font-variant:small-caps;
font-weight:bold;
font-size:12px;
line-height:1.5em;
font-family:"宋体",sans-serif;
}
这么多行的代码其实可以缩写为一句:
body{
font:italic small-caps bold 12px/1.5em "宋体",sans-serif;
}
1、使用这一简写方式你至少要指定 font-size 和 font-family 属性,其他的属性(如 font-weight、font-style、font-varient、line-height)如未指定将自动使用默认值。
2、在缩写时 font-size 与 line-height 中间要加入“/”斜扛。
一般情况下因为对于中文网站,英文还是比较少的,所以下面缩写代码比较常用:
body{
font:12px/1.5em "宋体",sans-serif;
}
只是有字号、行间距、中文字体、英文字体设置。
14、长度值
px(像素)、em、% 百分比,要注意其实这三种单位都是相对单位。
像素指的是显示器上的小点
em就是本元素给定字体的 font-size 值,如果元素的 font-size 为 14px ,那么 1em = 14px;如果 font-size 为 18px,那么 1em = 18px。
p{font-size:12px;line-height:130%}设置行高(行间距)为字体的130%(12 * 1.3 = 15.6px)。
15、居中
水平居中,内联元素水平居中text-align:center。
当被设置元素为块状元素时用 text-align:center 就不起作用了。这时也分两种情况:定宽块状元素和不定宽块状元素。
满足定宽和块状两个条件的元素是可以通过设置“左右margin”值为“auto”来实现居中的。
不定宽度的块状元素有三种方法居中(这三种方法目前使用的都比多):
加入 table 标签
设置 display;inline 方法
设置 position:relative 和 left:50%;
垂直居中-父元素高度确定的单行文本
设置父元素的 height 和 line-height 高度一致来实现
垂直居中-父元素高度确定的多行文本
1、 vertical-align是垂直居中属性,但只有父元素为tr和td的时候才有用。因此可以用table包含多行文本,实现垂直居中。注意:td 标签默认情况下就默认设置了 vertical-align 为 middle。
2、 通过设施display:table-cell; 激活 vertical-align 属性,但注意 IE6、7 并不支持这个样式。
display:table-cell;/*IE8以上及Chrome、Firefox*/
vertical-align:middle;/*IE8以上及Chrome、Firefox*/
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册