• webpack 官网
  • webpack 中文网
  • webpack 配置文件

概述

webpack 是一个现代 JavaScript 应用程序的模块打包器(module bundler)

webpack 是一个模块化方案(预编译)

webpack 获取具有依赖关系的模块,并生成表示这些模块的静态资源

webpack 的两个特点:模块化、打包

四个核心概念:入口(entry)输出(output)加载器(loader)插件(plugins)

模块化方案:webpack 和 requirejs(通过编写代码的方式将前端的功能,划分成独立的模块)
browserify 是与 webpack 相似的模块化打包工具

webpack 起源

  • webpack 解决了现存模块打包器的两个痛点:
    • Code Spliting - 代码分离
    • 静态资源的模块化处理方案

webpack 与模块

  • 前端模块系统的演进

  • 在 webpack 看来:所有的静态资源都是模块

  • webpack 模块能够识别以下等形式的模块之间的依赖:

    • ES2015 import export

    • CommonJS require() module.exports

    • AMD definerequire

    • css/sass/less 文件中的 @import

    • 图片连接,比如:样式 url(...) 或 HTML <img src=...>

    • 字体等

  • 在 webpack 提供的模块化环境中
    • 想要加载一个 JS 文件,只需要 require(‘a.js’)
    • 想要加载一个 CSS 文件,只需要 require(‘css/index.css’)
    • 想要加载一个图片文件,只需要 require(‘images/a.png’)
  • 入门 Webpack,看这篇就够了

webpack 打包原理:

​ 入口文件: main.js

​ webpack 从入口出发,递归分析项目中所有的依赖项(模块),使用 loader 来处理对应的模块最终,打包生成一个 bundle.js 文件。

​ 如果配置了 webpack 中的 代码分离(Code Spliting),webpack 会根据 分离点 将这个模块生成一个独立的 JS 文件

​ 还可以通过配置,将 CSS 、 图片、 字体 等文件,从 bundle.js 中抽离为独立的文件

webpack 的基本使用

安装:npm i -D webpack webpack-cli

webpack:是 webpack 工具的核心包

webpack-cli:提供了一些在终端中使用的命令

-D(–save-dev):表示项目开发期间的依赖

webpack 的两种使用方式:命令行、配置文件(webpack.config.js

命令行使用说明

  • package.json中的scripts中可以存放一些 bash 命令,这些 bash 命令可以通过 npm run 命令名称 来执行
  • 注意:npm 在执行 scripts 中的命令的时候,是在电脑系统后台默认开启一个 bash,将当前目录下的./node_modules/.bin这个文件夹临时加入了系统环境变量
  • 使用方式:npm run build
  • 设置开发状态: mode 如果没有设置 mode 配置项,webpack 会默认提供开发环境(production)
  • 在入口文件中可以使用 import 引入 js css less 等文件
"scripts": {
// webpack 是 webpack-cli 提供的命令
// src/js/main.js 为入口文件
// --output dist/bundle.js 为出口文件
// --mode development 生产环境
"build": "webpack"
"build1": "webpack src/js/main.js --output dist/bundle.js --mode development"
}

配置文件方式(推荐)

项目根目录下创建一个 webpack.config.js文件,运行 webpack 命令时的默认配置文件

指定其他文件:--config webpack.XX.js

配置 package.json 中的 scripts , 脚本命令为: "build": "webpack"

执行命令 : npm run build

示例代码

// webpack 是基于 node的 , 所以配置文件符合 node 方式书写配置
// 注意 : 不要再这个文件中使用ES6的的模块化 import语法
const path = require('path')
module.exports = {
// 入口
entry: path.join(__dirname, './src/js/main.js'),

// 出口
output: {
// 出口目录
path: path.join(__dirname, 'dist'),
filename: 'js/bundle.js'
},
// 开发模式
mode: 'development'
}

webpack-dev-server

安装:npm i -D webpack-dev-server

作用:配合 webpack,创建开发环境(启动服务器、监视文件变化、自动编译、刷新浏览器等),提高开发效率

注意:无法直接在终端中执行 webpack-dev-server,需要在 package.json 配置 scripts 后使用

使用说明

  • webpack-dev-server将打包好的文件存储在内存中,提高编译和加载速度,效率更高(不会生成 dist 目录)
  • 在内存中出口目录为项目根目录(命令行中的提示:webpack output is served from /
    • index.html页面中引入文件不需要加dist

CLI 配置

  • --contentBase :告诉服务器在哪个目录中提供服务(可以理解为:打开哪个目录中的 index.html)
    • --contentBase ./src:当前目录下的 src 文件夹
  • --open true :自动打开浏览器
  • --port 3000 :指定端口号
  • --hot :热更新,只加载修改的文件(按需加载修改的内容),而非全部加载
  • --progress:显示进度条
{
"scripts": {
"dev": "webpack-dev-server --contentBase src --open --port 8888 --hot"
}
}

配置文件配置

配置 package.json 中的 scripts , 脚本命令为: "dev": "webpack-dev-server --hot"

执行命令 : npm run dev

// --hot 热更新写在命令行里,不然的话还要配其他插件麻烦
module.exports = {
devServer: {
contentBase: path.join(__dirname, 'src'),
// 自动打开浏览器
open: true,
// 端口号
port: 3000,
// hot: true,

proxy: {
'/api': {
// api 表示当前项目请求的 key
target: 'http://www.baidu.com', // 代理服务器路径
pathRewrite: { '^/api': '/api' }, // 重写路径
changeOrigin: true
}
}
// 请求 localhost:8080/api/.. 会被代理到 http://www.baidu.com/api/..
}

// plugins: [
// new webpack.HotModuleReplacementPlugin()
// ]
}

html-webpack-plugin 插件

  • 安装:npm i -D html-webpack-plugin
  • 作用:根据模板,在内存中自动生成 html 页面,并自动引入bundle.jscss等文件

配置文件配置:

// 引入 html-webpack-plugin 插件
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// 配置插件
plugins: [
// html-webpack-plugin 配置
new HtmlWebpackPlugin({
// 模板页面路径
template: path.join(__dirname, 'src/index.html')
})
]
}

打包非 js 文件

webpack 默认只能处理 js 文件,非 js(css、less、图片、字体等)处理不了,借助 loader 加载器

处理 css 文件

main.js中引入 css 文件 import '../css/main.css'

安装 : npm i -D style-loader css-loader

webpack.config.js 中,添加个新的配置项 module

module 中添加 loader 来处理 css

module.exports = {
module: {
rules: [
// 处理 css
// 注意点 use 执行loader 顺序 从右往左
// css-loader: 读取css文件内容,将其转化为一个模块
// style-loader: 拿到模块, 创建一个style标签,插入页面中
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
}

处理 less 文件

main.js中引入 less 文件 import '../css/main.less'

安装 : npm i -D less-loader less style-loader css-loader

在 webpack.config.js 中配置项 module->rules中添加 loader 来处理 less

module.exports = {
module: {
rules: [
//处理 css
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
}
]
}
}

处理图片文件

安装 : npm i -D url-loader file-loader

在 webpack.config.js 中配置项 module->rules中添加 loader 来处理图片

module.exports = {
module: {
rules: [
// 处理图片
{
test: /\.(jpg|png)$/,
use: [
{
loader: 'url-loader',
options: {
// 图片大小 <= 10000 => 转化为base64
// 图片大小 >= 10000 => 不会转base64 内部调用 file-loader 加载图片
limit: 10000
}
}
]
}
]
}
}

url-loader 默认会将图片转化为 base64 编码格式,目的:提高性能

file-loader 在处理图片时,会对文件进行重命名

base64 编码格式的图片说明:

  • 精灵图:将一些小图片合并为一张图片,减少请求次数,提高性能
  • 字体图标:直接将一些小的图片,合并到字体文件中,并且不会失真
  • base64:是一种编码格式,能够将图片、文字等常见的文件,转化为 base64 格式,这种字符串格式浏览器能够识别并且读取显示到页面中
  • base64 是一个字符串,也可以直接被内嵌到页面中,或者 css 中
  • 注意:大图片不适合用 base64 处理,只有小的图标才适合 base64 处理

处理字体文件

main.js 中引入 css 文件 import '../css/iconfont/iconfont.css'

在 webpack.config.js 中配置

module.exports = {
module: {
rules: [
// 处理字体图标
{
test: /\.(svg|woff|woff2|ttf|eot)$/,
use: 'url-loader'
}
]
}
}

处理 ES6 语法

  1. 现在的项目都是使用 ES6 开发的,但是这些新的 ES6 语法,并不是所有的浏览器都支持,所以就需要有一个工具,帮我们转成 es5 语法,这个就是:babel
  2. babel
  3. Babel is a JavaScript compiler. ==> babel 是一个 JavaScript 编译器
  4. webpack 只能处理 import / export 这个 es6 模块化语法,而其他的 js 新语法,应该使用 babel 来处理

babel 的使用 :

  • 安装: npm i -D babel-core babel-loader@7
    • babel-core 是 babel 的核心包
    • babel-loader 加载 js 文件,并将 js 代码内容交给 babel-core 解析为 es5 低版本的 js
  • 安装:npm i -D babel-preset-env babel-preset-stage-2
    • babel-preset-env:表示能够解析 es2015、es2016、es2017、es2018 这些标准的语法
    • babel-preset-stage-2:用来解析还没有被采纳为标准的语法
    • babel-polyfill与babel-plugin-transform-runtime 也是做兼容处理的,以前都是用这个,兼容更早的
  • 配置 : 在 webpack.config.js 中添加一个 loader
module.exports = {
module: {
rules: [
// 处理 ES6 语法
{
test: /\.js$/,
use: 'babel-loader',
// 设置忽略 node-modules 文件夹
exclude: /node-modules/
}
]
}
}
  • 在项目根目录中创建 babel 的配置文件,叫:.babelrc
{
"presets": [
"env",
"stage-2"
],

-----------
// 暂时不用
// 如果未来某一天真的用到了polify
"plugins": [
"transform-runtime", {
"helpers": false,
"polyfill": true,
"regenerator": true,
"moduleName": "babel-runtime"
}
]
}

项目打包上线

执行 : npm run build 对项目进行打包,生成 dist 文件

模拟本地服务器 : 安装 : npm i -g http-server

把 dist 文件里的内容放到服务器里即可,直接运行http-server

webpack 和 gulp 区别

  1. Gulp 侧重于前端开发的整个过程的控制管理(像是流水线),我们可以通过给 gulp 配置不通的 task(通过 Gulp 中的 gulp.task() 方法配置,比如启动 server、sass/less 预编译、文件的合并压缩等等)来让 gulp 实现不同的功能,从而构建整个前端开发流程
  2. Webpack 也称之为模块打包机 ,由此也可以看出 Webpack 更侧重于模块打包,当然我们可以把开发中的所有资源(图片、js 文件、css 文件等)都可以看成模块,最初 Webpack 本身就是为前端 JS 代码打包而设计的,后来被扩展到其他资源的打包处理。Webpack 是通过 loader(加载器)和 plugins(插件)对资源进行处理的
  3. gulp 是构建工具,Webpack 是 js 模块化的解决方案

nodejs 基本介绍

为什么要学习 nodejs

  1. 降低编程语言切换的成本(nodejs 实质上用的还是 javascript)
  2. NodeJS 是前端项目的基础设施,前端项目中用到的大量工具 (大前端)
  3. nodejs 在处理高并发上有得天独厚的优势(利用 nodejs 做中间层)
  4. 对于前端工程师,面试时对于 nodejs 有一定的要求

node.js 是什么?

node.js,也叫作 node,或者 nodejs,指的都是一个平台

  1. node.js 官方网站
  2. node.js 中文网
  3. node.js 中文社区

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,nodejs 允许 javascript 代码运行在服务端

1. nodejs不是一门新的编程语言,nodejs是在服务端运行javascript的运行环境
2. 运行环境:写得程序想要运行必须要有对应的运行环境
php代码必须要有apache服务器
在web端,浏览器就是javascript的运行环境
在node端,nodejs就是javascript的运行环境
2. javascript并不只是能运行在浏览器端,浏览器端能够运行js是因为浏览器有js解析器,因此只需要有js解析器,任何软件都可以运行js。
3. nodejs可以在服务端运行js,因为nodejs是基于chrome v8的js引擎

nodejs 的本质:不是一门新的编程语言,nodejs 是 javascript 运行在服务端的运行环境,编程语言还是 javascript

nodejs 与浏览器的区别

相同点:nodejs 与浏览器都是 js 的运行环境,都能够解析 js 程序。对于 ECMAScript 语法来说,在 nodejs 和浏览器中都能运行

不同点:nodejs 无法使用 DOM 和 BOM 的操作,浏览器无法执行 nodejs 中的文件操作等功能

nodejs 可以干什么?

  1. 开发服务端程序
  2. 开发命令行工具(CLI),比如 npm,webpack,gulp,less,sass 等
  3. 开发桌面应用程序(借助 node-webkit、electron 等框架实现)

安装 nodejs

nodejs 版本

下载地址

  • 当前版本
  • 历史版本

官网术语解释

  • LTS 版本:Long-term Support 版本,长期支持版,即稳定版。
  • Current 版本:Latest Features 版本,最新版本,新特性会在该版本中最先加入

查看 node 版本

node -v

运行 nodejs 程序

方式一:使用 node 执行 js 文件

  • 创建 js 文件 helloworld.js

  • 写 nodejs 的内容:console.log('hello nodejs')

  • 打开命令窗口 cmd

    • shift 加右键打开命令窗口,执行 node 文件名.js即可
  • 执行命令:node helloworld.js

注意:在 nodejs 中是无法使用 DOM 和 BOM 的内容的,因此documentwindow等内容是无法使用的

方式二:REPL 介绍

  1. REPL 全称: Read-Eval-Print-Loop(交互式解释器)
    • R 读取 - 读取用户输入,解析输入了 Javascript 数据结构并存储在内存中
    • E 执行 - 执行输入的数据结构
    • P 打印 - 输出结果
    • L 循环 - 循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出
  2. 在 REPL 中编写程序 (类似于浏览器开发人员工具中的控制台功能)
    • 直接在控制台输入 node 命令进入 REPL 环境
  3. 按两次 Control + C 退出 REPL 界面 或者 输入 .exit 退出 REPL 界面
    • 按住 control 键不要放开, 然后按两下 c 键

环境变量

当要求系统运行一个程序 而没有告诉它程序所在的完整路径时

  1. 首先在当前目录中查找和该字符串匹配的可执行文件
  2. 进入用户 path 环境变量查找
  3. 进入系统 path 环境变量查找

配置环境变量:

找到环境变量:计算机 --右键--> 属性 --> 高级系统设置 --> 高级 --> 环境变量

global 模块-全局变量

JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。

在浏览器 JavaScript 中,通常 window 是全局对象, 而 Node.js 中的全局对象是 global,所有全局变量(除了 global 本身以外)都是 global 对象的属性。

在 Node.js 我们可以直接访问到 global 的属性,而不需要在应用中包含它。

常用的 global 属性

console: 用于打印日志
setTimeout/clearTimeout: 设置清除延时器
setInterval/clearInterval: 设置清除定时器

__dirname: 当前文件的路径,不包括文件名
__filename:当前文件的路径,包括文件名

// 与模块化相关的,模块化的时候会用到
require
exports
module

fs 模块

fs 模块是 nodejs 中最常用的一个模块,因此掌握 fs 模块非常的有必要,fs 模块的方法非常多,用到了哪个查哪个即可。

文档地址:http://nodejs.cn/api/fs.html

在 nodejs 中,提供了 fs 模块,这是 node 的核心模块

注意:

  1. 除了 global 模块中的内容可以直接使用,其他模块都是需要加载的。
  2. fs 模块不是全局的,不能直接使用。因此需要导入才能使用。
const fs = require('fs')

读取文件

语法:fs.readFile(file[, options], callback)

方式一:不传编码参数

// 参数1:文件路径
// 参数2:读取文件的回调函数
// 回调函数参数1:错误对象,如果读取失败,err 会包含错误信息,如果读取成功,err 是 null
// 回调函数参数2:读取成功后的数据(是一个Buffer对象)
fs.readFile('data.txt', function(err, data) {
console.log(err)
console.log(data)
console.log(data.toString()) // 将Buffer对象转换成字符串
})

方式二:传编码参数

// 参数1:文件的路径
// 参数2:编码,如果设置了,返回一个字符串,如果没有设置,会返回一个buffer对象
// 参数3:回调函数
fs.readFile('data.txt', 'utf8', function(err, data) {
console.log(err)
console.log(data)
})

关于 Buffer 对象

1. Buffer对象是Nodejs用于处理二进制数据的
2. 其实任意的数据在计算机底层都是二进制数据,因为计算机只认识二进制
3. 所以读取任意的文件,返回的结果都是二进制数据,即Buffer对象
4. Buffer对象可以调用toString()方法转换成字符串

写文件

语法:fs.writeFile(file, data[, options], callback)

// 参数1:文件路径(如果文件不存在,会自动创建)
// 参数2:写入的文件内容(注意:写入的内容会覆盖以前的内容)
// 参数3:写文件后的回调函数
fs.writeFile('2.txt', 'hello world', function(err) {
if (err) return console.log('写入文件失败', err)
console.log('写入文件成功')
})

注意:

  1. 写文件的时候,会把原来的内容给覆盖掉

语法:fs.appendFile(path, data[, options], callback)

// 参数1:追加的文件名(如果文件不存在,会自动创建)
// 参数2:追加的文件内容
// 参数3:追加文件后的回调函数
fs.appendFile('2.txt', '我是追加的内容', function(err) {
if (err) return console.log('追加文件内容失败')
console.log('追加文件内容成功')
})

思考:如果没有 appendFile,通过 readFile 与 writeFile 应该怎么实现?

文件同步与异步的说明

fs 中所有的文件操作,都提供了异步和同步两种方式

异步方式:不会阻塞代码的执行

// 异步方式
const fs = require('fs')

console.log(111)
fs.readFile('2.txt', 'utf8', function(err, data) {
if (err) {
return console.log('读取文件失败', err)
}
console.log(data)
})
console.log('222')

同步方式:会阻塞代码的执行

//同步方式
console.log(111)
const result = fs.readFileSync('2.txt', 'utf-8')
console.log(result)
console.log(222)

总结:同步操作使用虽然简单,但是会影响性能,因此尽量使用异步方法,尤其是在工作过程中。

其他 api(了解)

方法有很多,但是用起来都非常的简单,学会查文档

文档:http://nodejs.cn/api/fs.html

方法名 描述
fs.readFile(path, callback) 读取文件内容(异步)
fs.readFileSync(path) 读取文件内容(同步)
fs.writeFile(path, data, callback) 写入文件内容(异步)
fs.writeFileSync(path, data) 写入文件内容(同步)
fs.appendFile(path, data, callback) 追加文件内容(异步)
fs.appendFileSync(path, data) 追加文件内容(同步)
fs.rename(oldPath, newPath, callback) 重命名文件(异步)
fs.renameSync(oldPath, newPath) 重命名文件(同步)
fs.unlink(path, callback) 删除文件(异步)
fs.unlinkSync(path) 删除文件(同步)
fs.mkdir(path, mode, callback) 创建文件夹(异步)
fs.mkdirSync(path, mode) 创建文件夹(同步)
fs.rmdir(path, callback) 删除文件夹(异步)
fs.rmdirSync(path) 删除文件夹(同步)
fs.readdir(path, option, callback) 读取文件夹内容(异步)
fs.readdirSync(path, option) 读取文件夹内容(同步)
fs.stat(path, callback) 查看文件状态(异步)
fs.statSync(path) 查看文件状态(同步)

path 模块

路径操作的问题

在读写文件的时候,文件路径可以写相对路径或者绝对路径

data.txt 是相对路径,读取当前目录下的 data.txt,相对路径相对的是指向 node 命令的路径

// 如果node命令不是在当前目录下执行就会报错,在当前执行node命令的目录下查找data.txt,找不到
fs.readFile('data.txt', 'utf8', function(err, data) {
if (err) {
return console.log('读取文件失败', err)
}

console.log(data)
})

相对路径:相对于执行 node 命令的路径

推荐使用绝对路径:__dirname: 当前文件的目录,__filename: 当前文件的目录,包含文件名

path 模块的常用方法

关于路径,在 linux 系统中,路径分隔符使用的是/,但是在 windows 系统中,路径使用的\

在我们拼写路径的时候会带来很多的麻烦,经常会出现 windows 下写的代码,在 linux 操作系统下执行不了,path 模块就是为了解决这个问题而存在的。

常用方法:

path.join() // 拼接路径,返回拼接后的结果

// windows系统下
path.join('abc', 'def', 'gg', 'index.html')
'abc\def\gg\a.html'

// linux系统下
path.join('abc','def','gg', 'index.html')
'abc/def/gg/index.html'

【优化读写文件的代码】

其他方法:
path.basename(path[, ext]) 返回文件的最后一部分
path.dirname(path) 返回路径的目录名
path.extname(path) 获取路径的扩展名(后缀名)

var path = require('path')
var temp = 'abc\\def\\gg\\a.html'
console.log(path.basename(temp)) //a.html
console.log(path.dirname(temp)) //abc\def\gg
console.log(path.extname(temp)) //.html

path 模块其他 api(了解)

方法名 描述
path.basename(path[, ext]) 返回文件的最后一部分
path.dirname(path) 返回路径的目录名
path.extname(path) 获取路径的扩展名
path.isAbsolute(path) 判断目录是否是绝对路径
path.join([...paths]) 将所有的 path 片段拼接成一个规范的路径
path.normalize(path) 规范化路径
path.parse(path) 将一个路径解析成一个 path 对象
path.format(pathObj) 讲一个 path 对象解析成一个规范的路径

http 模块

创建服务器基本步骤

// 1. 导入http模块,http模块是node的核心模块,作用是用来创建 http 服务器的
const http = require('http')

// 2. 创建服务器
let server = http.createServer()

// 3. 服务器处理请求
server.on('request', (req, res) => {
console.log('我接收到请求了')
})

// 4. 启动服务器,监听某个端口
server.listen(9999, (err) => {
console.log('服务器启动成功了, 请访问: http://localhost:9999')
})

详细说明

  1. 给服务器注册 request 事件,只要服务器接收到了客户端的请求,就会触发 request 事件
  2. request 事件有两个参数,req 表示请求对象,可以获取所有与请求相关的信息,res 是响应对象,可以获取所有与响应相关的信息
  3. 服务器监听的端口范围为:1-65535 之间,推荐使用 3000 以上的端口,因为 3000 以下的端口一般留给系统使用

request 对象详解

文档地址:http://nodejs.cn/api/http.html#http_message_headers

常见属性:

headers: 所有的请求头信息
method:请求的方式
rawHeaders:所有的请求头信息(数组的方式)
url:请求的地址(url地址的路径部分)
请求 http://127.0.0.1:3000/index 获取到的是:/index
请求 http://127.0.0.1:3000 获取到的是:/

注意:在发送请求的时候,可能会出现两次请求的情况,这是因为谷歌浏览器会自动增加一个favicon.ico的请求

小结:request 对象中,常用的就是 method 和 url 两个参数

response 对象详解

文档地址:http://nodejs.cn/api/http.html#http_class_http_serverresponse

常见的属性和方法:

res.write(data): 给浏览器发送响应体,可以调用多次,从而提供连续的响应体
res.end():通知服务器,所有响应头和响应主体都已被发送,即服务器将其视为已完成
res.end(data):结束请求,并且响应一段内容,相当于res.write(data) + res.end()
res.statusCode: 响应的的状态码 200 404 500
res.statusMessage: 响应的状态信息(不能有中文), 如果不设置会根据statusCode自动设置
res.setHeader(name, value):设置响应头信息,比如'content-type''text/html;charset=utf-8'
res.writeHead(statusCode, statusMessage, options):设置响应头,同时可以设置状态码和状态信息
options 是对象,写响应头的键值对

注意:必须先设置响应头,才能设置响应主体。

  • 注意:浏览器中输入的 URL 地址,仅仅是一个标识,可以不与服务器中的文件路径一致。也就是说:返回什么内容是由服务端的逻辑决定

  • 路由 : url 标示和对应文件/数据的一一对应关系

模拟 Apache 服务器

  • 根据 req.url 读取不同的页面内容,返回给浏览器
// 需求: 简单模仿apache服务器,浏览器发送127.0.0.1:8888/index.html
// 对应的返回www文件夹下面的index.html的内容
const fs = require('fs')
const http = require('http')
const path = require('path')

// 创建服务器
let server = http.createServer()
// 监听请求
server.on('request', (req, res) => {
// 根据不同请求输出不同响应数据
if (req.url === '/' || req.url === '/i') {
// 读取www下面的index.html
let filename = path.join(__dirname, 'www', 'index.html')
fs.readFile(filename, 'utf-8', (err, data) => {
if (err) console.log('文件读取失败')
// 服务器响应文件
res.statusCode = 200
res.statusMessage = 'ok'
res.setHeader('content-type', 'text/html;charset=utf-8')
res.end(data)
})
} else if (req.url === '/l') {
// 读取list.html
let filename = path.join(__dirname, 'www', 'list.html')
fs.readFile(filename, 'utf-8', (err, data) => {
if (err) return console.log('文件读取失败')
// 服务器响应文件
res.writeHead(200, 'OOOOOOK', {
'content-type': 'text/html;charset=utf-8'
})
res.end(data)
})
} else {
// 返回浏览器, 未找到资源
res.writeHead(404, 'NOT FOUND', {
'content-type': 'text/html;charset=utf-8'
})
res.end('404 ,资源未找到')
}
})
// 开启服务器

server.listen(8888, () => {
console.log('服务器开启了')
})

MIME 类型

  • MIME(Multipurpose Internet Mail Extensions)多用途 Internet 邮件扩展类型 是一种表示文档性质和格式的标准化方式
  • 浏览器通常使用 MIME 类型(而不是文件扩展名)来确定如何处理文档;因此服务器将正确的 MIME 类型附加到响应对象的头部是非常重要的
  • MIME 类型

mime 模块

  • 作用:获取文件的 MIME 类型
  • 安装:npm i mime
let mime = require('mime')

// 获取路径对应的 MIME 类型
mime.getType('txt') // 'text/plain'
// 根据 MIME 获取到文件后缀名
mime.getExtension('text/plain') // 'txt'

nodemon 自动重启

  • 作用:监听到 js 文件修改后,自动重启 node 程序
  • 安装:npm i -g nodemon
  • 使用:nodemon app.js 运行 node 程序

hacknews 案例

  • Hacker News 示例
  • 路由(route):就是一套映射规则,根据 url 地址分配到对应的处理程序

功能划分

  • 1 新闻列表页 - /index get
  • 2 新闻详情页 - /details get
  • 3 新闻添加页 - /submit get
  • 4 新闻添加请求 - /add post

art-template 模板引擎

  • 文档
  • 安装
npm install art-template
  • 核心方法
// 基于模板路径渲染模板
// 参数1:文件的路径
// 参数2:数据
// 返回值:返回渲染后的内容
// template(filename, data)
let html = template(path.join(__dirname, 'pages', 'index.html'), { name: '大吉大利,今晚吃鸡' })

注意点:文件的路径必须是绝对路径;会将整个 html 当做模板返回

url 模块

  • 说明:用于 URL 处理与解析
  • 注意:通过 url 拿到的查询参数都是字符串格式
// 导入url模块
var url = require('url')

// 解析 URL 字符串并返回一个 URL 对象
// 第一个参数:表示要解析的URL字符串
// 第二个参数:是否将query属性(查询参数)解析为一个对象,如果为:true,则query是一个对象
var ret = url.parse('http://localhost:3000/details?id=1&name=jack', true)
console.log(ret.query) // {id: '1', name: 'jack'}

querystring 模块

  • 用于解析与格式化 URL 查询字符串
  • 注意:只在专门处理查询字符串时使用
// foo=bar&abc=xyz&abc=123
var querystring = require('querystring')

// 将查询参数转化为对象
// 第一个参数: 要解析的 URL 查询字符串
querystring.parse('foo=bar&abc=xyz') // {foo: 'bar', abc: 'xyz'}

服务端重定向

  • HTTP 状态码说明
  • 301 和 302
  • 说明:服务端可以通过 HTTP 状态码让浏览器中的页面重定向
res.writeHead(302, {
Location: '/'
})
res.end()

POST 请求参数的处理

  • 说明:POST 请求可以发送大量数据,没有大小限制
// 接受POST参数
var postData = []

// data事件:用来接受客户端发送过来的POST请求数据
var result = ''
req.on('data', (chunk) => {
result += chunk
})

// end事件:当POST数据接收完毕时,触发
req.on('end', () => {
cosnole.log(result)
})

模块化改造 hackerNews

Less 简介

Less  是一门 CSS 预处理语言(预先处理),它扩展了 CSS 语言,增加了变量、Mixin、函数等特性

浏览器不直接识别 less 文件,浏览器只识别 css 文件,所以我们写了 less 文件之后,我们需要预先把 less 文件转换成 css 文件。

本质上,LESS 包含一套自定义的语法及一个解析器,用户根据这些语法定义自己的样式规则,这些规则最终会通过解析器,编译生成对应的 CSS 文件。LESS 并没有裁剪 CSS 原有的特性,更不是用来取代 CSS 的,而是在现有 CSS 语法的基础上,为 CSS 加入程序式语言的特性。

less 仅仅是写 css 的另一种方式,写出来的 less 文件浏览器也不识别,所以啊,我们写完了 less 文件,还需要通过 less 解析器解析成 css,最终浏览器引入的还是 css 文件。

学习网站:

官网 http://lesscss.org/
中文网 http://lesscss.cn/

less 的编译

如何把 less 文件变成 css 文件

使用打包工具

gulp

webpack

使用考拉

koala 是一个前端预处理器语言(less/sass)图形编译工具,支持 Less、Sass、Compass、CoffeeScript,帮助 web 开发者更高效地使用它们进行开发。跨平台运行,完美兼容 windows、linux、mac。

考拉官网

使用步骤:

  1. less文件夹拖进去
  2. 会在当前目录生成一个css目录

优点:不用 node 环境,不用 less 环境,koala 内置了

使用插件

easy less

Less 语法

变量

注释

/* 这是CSS中的注释,因此会编译到css中 */
// 这是less的注释,css不能识别这个注释, 最后不会编译到css文件

变量

// @变量名: 变量值;
@color: #ccc;
p {
color: @color;
}

mixin 函数

混入函数

// 定义一个函数:不带参数
.btn() {
background-color: #ccc;
}
// 调用函数
.my_btn {
.btn();
}

// 定义一个函数:带参数
.btn_border(@width) {
border: @width solid #000;
}
.my_btn {
// 如果函数定义了参数,调用的时候必须传入参数,否则会报错
.btn_border(10px);
}

// 定义一个函数:带参数默认值
.btn_border(@width: 1px) {
border: @width solid #000;
}
.my_btn {
// 因为有默认值,所以不会报错
.btn_border();
.btn_border(10px);
}

应用:定义兼容多浏览器的圆角

.border_radius(@value: 5px) {
-webkit-border-radius: @value;
-moz-border-radius: @value;
-ms-border-radius: @value;
border-radius: @value;
}
div {
.border_radius(10px);
}

嵌套

我们可以在一个选择器中嵌套另一个选择器来实现继承,这样很大程度减少了代码量,并且代码看起来更加的清晰。

  • 使用伪类的时候 可以使用& 表示自己
.father {
width: 100px;
// 子代
.son1 {
}
// 后代
> .son2 {
}
// 交集: & 表示本身
&.now {
}
&::before {
}
&:hover {
}
}

导入

// 可以省略后缀名
@import 'variable';
@import 'maxin';

模块化的思想,分模块进行管理这些 less 文件,最终只需要使用 import 将 less 引入到一起即可

函数(运算)

在我们的 CSS 中充斥着大量的数值型的 value,less 可以直接支持运算,也提供了一系列的函数提供给我们使用。

li {
float: left;
width: round(100%/6, 2);
height: 100px + 100px;
}

http://www.1024i.com/demo/less/reference.html

移动 web 基础

移动端开发现状

  • 移动 web 开发指的是需要适配移动设备的网页开发
  • 移动 web 开发与 pc 端 web 开发没有本质的区别,使用的还是 HTML/CSS/JavaScript 的技术
  • 移动 web 开发与 pc 端 web 开发的区别是什么?

移动端的浏览器与 pc 端不同

谷歌浏览器 苹果浏览器、 UC浏览器 QQ浏览器 欧朋浏览器 百度手机浏览器  360安全浏览器  搜狗浏览器  猎豹浏览器等
国内的手机浏览器都是根据webkit内核修改过来的,国内没有自主研发的内核,国内的操作系统也是基于Android系统修改的。

因此在移动端,css3 属性只需要加 webkit 前缀即可

移动端设备尺寸不一样(尺寸非常多,碎片化很严重)

Android320*480 480*800  540*960 720*1280 1080*1920 2k屏 4k屏
iphpne: 640*960 640*1136 750*1334 1242*2208

移动端开发分类

  • 原生 app(native app)
  • 混合 app(Hybrid app)
  • web 应用(webApp)

原生 app(native app)

原生 app 是基于操作系统的开发,比如安卓,ios,windows phone,他们只能在各自的操作系统上运行。

优点:

  1. 可以访问操作系统,获取更多的资源(gps,摄像头,传感器,麦克风等)
  2. 速度快,性能高,用户体验好
  3. 可以离线使用

缺点:

  1. 开发成本高
  2. 需要安装和更新,更新与发布需要审核。

Web App

Web 应用使用 H5C3 开发页面,为浏览器设计的基于 web 的应用,可以在各种智能设备的手机浏览器上运行。不需要安装即可运行。

优点:

  1. 支持设备广泛
  2. 开发成本低(使用)
  3. 可以随时上线与更新,无需审核

缺点:

  1. 用户体验极度依赖网速
  2. 要求联网
  3. 无法获取手机的资源(gps,摄像头)

混合 app(Hybrid App)

Hybrid App 是指介于 web-app、native-app 这两者之间的 app,它虽然看上去是一个 Native App,但只有一个 UI WebView,里面访问的是一个 Web App。(淘宝、京东、手机百度)

Hybird App 说白了就是使用了 Native app 的壳,里面其实还是 HTML5 页面

优点:

  1. 开发成本和难度更低,兼容多个平台
  2. 也可以访问手机的操作系统资源。
  3. 更新维护更方便

缺点:

  1. 用户体验相比原生 app 稍差
  2. 性能依赖于网速

总结:

三种开发各有优缺点,具体用什么需要根据实际情况而定,比如预算,app 注重功能还是内容等

屏幕与分辨率

理解设备像素、设备独立像素和 css 像素

移动设备与 PC 设备最大的差异在于屏幕,这主要体现在屏幕尺寸和屏幕分辨率两个方面

屏幕尺寸

通常我们所指的屏幕尺寸,实际上指的是屏幕对角线的长度(一般用英寸来度量)

1英寸 = 2.54厘米

屏幕分辨率

分辨率则一般用像素来度量,表示屏幕水平和垂直方向的像素数,例如 1920*1080 指的是屏幕垂直方向和水平方向分别有 1920 和 1080 个像素点而构成

像素:指计算机显示设备中的最小单位,即一个像素点的大小。每一个像素点可以理解为就是屏幕上的一个发光点

像素密度 ppi

PPI (Pixels Per Inch)表示屏幕每英寸的像素数

PPI 值的越大说明单位尺寸里所能容纳的像素数量就越多,所能展现画面的品质也就越精细,反之就越粗糙

设备像素

设备像素 (device pixels)也叫物理像素

设备像素指的是显示器上的真实像素,每个像素的大小是屏幕固有的属性,屏幕出厂以后就不会改变了

设备分辨率描述的就是这个显示器的宽和高分别是多少个设备像素

设备像素和设备分辨率交给操作系统来管理,浏览器不知道、也不需要知道设备分辨率的大小,浏览器只需要知道逻辑分辨率就可以了

设备独立像素

设备独立像素(Device Independent Pixels)也叫逻辑像素、设备无关像素。在 IOS 设备上叫PT,Android 设备上叫DP,在 css 中,叫PX

为了能够保证 图像内容在不同的 PPI 设备看上去大小应该差不多 ,操作系统定义了一个单位:设备独立像素,用设备独立像素定义的尺寸,不管屏幕的参数如何,都能以合适的大小显示(这也是设备独立像素名字的由来)

对于那些像素密度高的屏幕,操作系统将多个设备像素划分为一个逻辑像素。屏幕的像素密度越高,就需要更多的设备像素来显示一个设备独立像素。至于将多少设备像素划分为一个逻辑像素,这由操作系统决定

获取设备的像素比

window.devicePixelRatio // 物理像素 与 css 像素的比值 DPR

通过 screen.width/height得到的屏幕宽度和高度就是逻辑分辨率(单位:设备独立像素)

css 像素与缩放

在缩放比例为 100% 的情况下,一个 css 像素大小等于一个设备独立像素

缩放页面的时候,元素的 css 像素数量不会改变,改变的只是每个 css 像素的大小

缩放比例 = css 像素边长 / 设备独立像素边长

如果原本元素宽度为 128 个设备独立像素,那么缩放 200% 以后元素宽度为 256 个设备独立像素(css 像素宽度始终是 128)

桌面浏览器上缩放机制是 page zoom,缩放会导致 CSS 像素边长的改变,从而导致 window.devicePixelRatio 的改变

在移动端缩放机制是 pinch zoom,计算 window.devicePixelRatio 时,不考虑 pinch zoom 对 CSS 像素尺寸的影响,因此 window.devicePixelRatio 不会随缩放而改变

2 倍图与 3 倍图

以后同学在工作的过程中,从 UI 那拿到的设计图通常都是 640 的设计图或者是 750 的设计图

把更多的像素点压缩至一块屏幕里,从而达到更高的分辨率并提高屏幕显示的细腻程度

设备像素比 devicePixelRatio:即像素的压缩比例

结论 :在移动端为了在高清屏手机上显示得更加细腻,通常会使用更大的图片,比如 2 倍图或者 3 倍图

视口 viewport

问题:一个电脑上的网站,在手机端访问,效果是什么样的?

iPhone5 的设备宽度只有 320px,一张宽度为 640px 的图片在手机端访问,显示的效果是什么?

1. 在手机端,html的 大小都是 980px,为什么?
这主要是历史原因导致的,因为在移动设备刚流行的时候,网站大多都是pc端的,pc端的页面宽度一般都比较大,移动设备的宽度比较小,如果pc端页面直接在移动端显示的话,页面就会错乱。为了解决这个问题,移动端html的大小直接就定死成了980px(因为早起的pc端网站版心就是980px居多)

2. 视口
在 pc 端,html 的大小默认是继承了浏览器的宽度,即浏览器多宽,html 的大小就是多宽,但是在移动端,多出来了一个视口的概念(乔布斯),视口说白了就是介于浏览器与 html 之间的一个东西,视口的宽度默认定死了 980px,因此 html 的宽度默认就是 980px,视口的特点是能够根据设备的宽度进行缩放

3. 视口设置
对于现在的移动端页面来说,视口默认为 980px 肯定不合适,因为设备宽度不够的话,视口会进行缩放,导致页面展示效果不好看

视口参数设置

// width 设置视口的宽度
// width=device-width 设置视口宽度为设备的宽度(常用)

// initial-scale 设置初始缩放比例
// initial-scale=1.0 表示不缩放

// user-scalable 设置是否允许用户缩放
// user-scalable=no 不允许用户缩放

// maximum-scale 设置允许的最大缩放比例
// maximum-scale=1.0 可以不设置,因为都禁止用户缩放了

// minimum-scale 设置允许最小缩放比
// minimum-scale=1.0 不设置,因为都禁用用户缩放了


// 标准写法:
// 快捷键: meta:vp + tab键
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">

移动端调试问题

  1. 模拟器调试
  2. 真机调试:使用手机进行访问。

手机设备五花八门,屏幕尺寸都大不一样,尤其是安卓端,给我们的页面预览带来了一些麻烦。在实际工作中,作为开发者不可能有足够的设备让我们去测试(除了测试部门 ),即便有,效率也特别的低,因此开发者一般都是通过浏览器的手机模拟器来模拟不同的设备。

流式布局

移动端的特点

  • 手机端的兼容性问题比 PC 端小很多,因为手机端的浏览器版本比较新
  • 手机端屏幕比较小,能够放的内容比较少。

问题:布局的时候怎么解决屏幕大小不一致的问题?

  • PC 端,固定版心,让所有分辨率的电脑的版心都是一样的,比如京东
  • 移动端:移动端无法设置版心,因为移动端的设备屏幕本身就小,设置版心不合适。因此移动端大多会采用流式布局(百分比布局)

流式布局,也叫百分比布局,是移动端开发中经常使用的布局方式之一。

流式布局的特征:

  • 宽度自适应,高度写死,并不是百分百还原设计图
  • 图标都是固定死大小的,包括字体等也是固定死的。并不是所有的东西都是自适应的。
  • 一些大的图片,设置宽度为百分比自适应即可,随着屏幕大小进行变化

流式布局无法做到所有设备都非常逼真的还原设计图,有些设备显示效果不是特别的好看。但是流式布局是移动端非常常用的一种布局方式,比较简单,需要掌握(携程、京东)

最后一天会学习 rem 布局,配合 less 非常的方便,并且能够实现完全的自适应,包括字体以及图标等

经典的流式布局

1. 左侧固定,右侧自适应
2. 右侧固定,左侧自适应
3. 两侧固定,中间自适应(圣杯布局,双飞翼布局)
4. 等分布局

touch 事件

移动端新增了 4 个与手指触摸相关的事件

  • touchstart: 手指放到屏幕上时触发
  • touchmove: 手指在屏幕上滑动式触发(会触发多次)
  • touchend: 手指离开屏幕时触发
  • touchcancel: 系统取消 touch 事件的时候触发,比如电话

每个触摸事件被触发后,会生成一个 event 对象,event 对象中changedTouches会记录手指滑动的信息

e.touches // 当前屏幕上的手指
e.targetTouches // 当前dom元素上的手指。
e.changedTouches // 触摸时发生改变的手指(重点)(如手指离开屏幕)

这些列表里的每次触摸由 touch 对象组成,touch 对象里包含着触摸信息,主要属性如下

// e.changedTouches[0].clientX
clientX / clientY // 触摸点相对浏览器窗口的位置
pageX / pageY // 触摸点相对于页面的位置

!> 使用 jquery 注册 touch 类事件时,获取手指使用 e.originalEvent.touchs[0] ,因为 jq 对事件对象进行了封装

【案例:jdm-滑动轮播图】

【案例:jdm-区域滚动】

iscroll 插件使用

https://github.com/cubiq/iscroll

iscroll 参考文档

注意:使用 iscroll 需要满足的条件

  1. 父盒子嵌套了子盒子(一个)
  2. 如果有多个子盒子,所以我们需要使用一个盒子把所有的子盒子包裹起来
  3. 如果有图片,我们需要保证图片加载完成,如果有浮动,需要清除浮动,为了保证子盒子的高度获取的是正确的
  4. 子盒子大小一定要超过父盒子的大小
// 使用:box为父盒子
var box = document.querySelector('.box')
new IScroll(box, {
scrollX: false, // 横向滚动
scrollY: true // 纵向滚动
})

zepto 框架

Zepto是一个轻量级的针对现代高级浏览器的 JavaScript 库, 它与 jquery有着类似的 api。 如果你会用 jquery,那么你也会用 zepto

github 地址

中文文档

zepto 与 jquery 的区别

  • jquery 针对 pc 端,主要用于解决浏览器兼容性问题,zepto 主要针对移动端
  • zepto 比 jquery 轻量,文件体积更小
  • zepto 封装了一些移动端的手势事件

zepto 的基本使用

zepto 的使用与 jquery 基本一致,zepto 是分模块的,需要某个功能,就需要引入某个 zepto 的文件

<script src="zepto/zepto.js"></script>
<script src="zepto/event.js"></script>
<script src="zepto/fx.js"></script>
$(function() {
$('.box').addClass('demo')

$('button').on('click', function() {
$('.box').animate({ width: 500 }, 1000)
})
})

zepto 的定制

安装 Nodejs 环境

1、下载 zepto.js

2、解压缩

3、cmd 命令行进入解压缩后的目录

4、执行npm install命令

5、编辑 make 文件的41行,添加自定义模块并保存

7、然后执行命令 npm run-script dist

8、查看目录 dist 即构建好的 zepto.js

zepto 手势事件

zepto 中根据touchstart touchmove touchend封装了一些常用的手势事件,这些事件都是基于 touchstart touchmove touchend 封装

tap // 轻触事件,用于替代移动端的click事件,因为click事件在老版本中会有300ms的延迟
swipe //手指滑动时触发
swipeLeft //左滑
swipeRight //右滑
swipeUp //上滑
swipeDown //下滑

响应式

什么是响应式布局

响应式布局(respond layout)是 Ethan Marcotte 在 2010 年 5 月份提出的一个概念,简而言之,就是一个网站能够兼容多个终端(手机、平板、pc 电脑、手表) ——而不是为每个终端做一个特定的版本。这个概念是为解决移动互联网浏览而诞生的

为什么要有响应式布局?

  • 在移动互联日益成熟的时候,在 PC 端开发的网页已经无法满足移动设备的要求
  • 通常的做法是针对移动端单独做一套特定的版本
  • 如果终端越来越多,那么需要开发的版本就会越来越多(大屏设备的普及)
  • 响应式布局 :一个网站能够兼容多个终端(节约开发成本)

优点:

面对不同分辨率设备灵活性强

能够快捷解决多设备显示适应问题

**缺点: **

兼容各种设备工作量大,效率低下

代码累赘,会出现隐藏无用的元素,加载时间加长

其实这是一种折中性质的设计解决方案,多方面因素影响而达不到最佳效果

一定程度上改变了网站原有的布局结构,会出现用户混淆的情况

响应式开发现状:

  • 如果已经存在 PC 的网站了,那么一般不会使用响应式开发,而是针对移动端再开发一套系统(比如京东、淘宝)
  • 新建站点 上采用响应式开发的越来越多
  • 在国内,响应式开发还不是特别的流行。但响应式开发是大势所趋,会越来越流行

响应式开发与移动 web 开发的比较

开发方式 移动 web 开发+pc 开发 响应式开发
引用场景 一般已经有了 PC 端网站,只需要端独开发移动端网站即可 针对一些新建网站,并且要求适配移动端
开发 针对性强,开发效率高 兼容各种终端,效率低
适配 只能适配移动端或者 PC 端,pad 上体验比较差 可以适配各种终端
效率 代码简介,加载快 代码相对复杂,加载慢

媒体查询

媒体查询(Media Query)是 CSS3 提出来的一个新的属性,通过媒体查询可以查询到 screen 的宽度,从而指定某个宽度区间的网页布局

设备分类

分类 宽度范围
大屏设备 >1200px
中屏设备 992px~1200px
小屏设备 768px~992px
超小屏设备 < 768px

媒体查询的使用

需求:

<!--
大屏设备(>1200px) 版心:1170px 背景色:红色
中屏设备(992-1200) 版心:970px 背景色:蓝色
小屏设备(768-992) 版心:750px 背景色:黄色
超小屏设备(<768px) 版心:100% 背景色:绿色
-->

响应式开发的原理:使用媒体查询实现不同终端的布局和样式的切换

媒体查询语法:

/* 查询屏幕 */
/* screen 和第一个 and 可以省略 */
@media screen and 条件 {
}

/* 条件的写法 */
/* min-width: 只要屏幕宽度超过这个值的设备样式就能生效 */
/* max-width: 只要屏幕宽度小于这个值的设备样式就能生效 */
@media screen and (min-width: 1200px) {
.container {
width: 1170px;
background-color: red;
}
}

@media screen and (min-width: 992px) and (max-width: 1200px) {
.container {
width: 970px;
background-color: blue;
}
}

@media screen and (min-width: 768px) and (max-width: 992px) {
.container {
width: 750px;
background-color: yellow;
}
}

@media screen and (max-width: 768px) {
.container {
width: 100%;
background-color: green;
}
}

bootstrap 框架

【项目:微金所】

REM

rem 是什么?

rem(font size of the root element)是指相对于根元素的字体大小的单位。它就是一个相对单位。

em(font size of the element)是指相对于 当前元素的字体大小 的单位。它也是一个相对单位。

它们之间其实很相似,只不过计算的规则一个是依赖根元素,一个是当前元素计算。

html {
font-size: 16px;
}
body {
font-size: 20px;
}
div.em {
/* em 的计算方式参照的当前元素的 font-size,如果不设置,默认继承自父盒子 */
width: 2em;
height: 2em;
background-color: red;
}
/* rem 的计算方式参照的是 html 的 font-size */
div.rem {
width: 2rem;
height: 2rem;
background-color: blue;
}

为什么要用 rem?

rem 的主要目的就是解决用于不同屏幕的适配问题。rem 能够等比例的适配所有的屏幕。

由于市面上手机种类繁多,导致移动端的屏幕种类非常的混乱,比如有常见的320px 360px 375px 384px 480px 640px等。在开发中,美工一般只会提供 750px 或者是 640px 的设计稿,这就要求我们通过一张设计稿能够适配所有的屏幕。通常解决方案如下:

  • 流式布局:虽然可以让各种屏幕都适配,但是显示效果不是非常的友好,因为只有几个尺寸的手机能够完美的显示出来视觉设计师和交互最想要的效果。但是目前使用流式布局的公司非常多,比如 亚马逊京东携程
  • 响应式布局:响应式这种方式在国内很少有大型企业的复杂性的网站在移动端用这种方法去做,主要原因是工作大,维护性难 。所以一般都是中小型的门户或者博客类站点会采用响应式的方法从 PC 端页面到移动端页面以及 web app 直接一步到位,因为这样反而可以节约成本。
  • rem 布局:rem 能够适配所有的屏幕,与 less 配合使用效果会更好。目前使用 rem 布局的有:淘宝苏宁

rem 布局

因为 rem 的基准点是根元素 html 的字体大小,因此我们只需要设置不同屏幕的 html 的 font-size 大小不一样就可以达到不同屏幕的适配了。

rem 配合媒体查询

使用 rem 配合媒体查询可以适配多个终端

@media(min-width: 320px) {
html {
/* 基准值 / 设计图的大小 = 某个屏幕的font-size / 屏幕的宽度 */
/* 100/750 = x/370 */
font-size: 50px;
}
}
...

优点:使用媒体查询适配,速度快。

缺点:适配多个终端时,需要添加响应的代码。

rem 配合 javascript

通过 javascript 获取可视区的宽度,计算 font-size 的值,也可以适配多个终端

// 根据屏幕的大小动态设置 html的 font-size
function responsive () {
var uiWidth = 750 // 设计图宽度
var base = 100 // 设计图中1rem的大小
// 当前屏幕的大小
var pageWidth = window.innerWidth
if(pageWidth >= 750) {
pageWidth = 750
}
if(pageWidth <= 320) {
pageWidth = 320
}
// 说白了就是把一个屏幕分成了 7.5 rem
document.documentElement.style.fontSize = (base / uiWidth * pageWidth).toFixed(2) + ’px‘
}

优点:直接适配所有的终端

缺点:必须在页面加载之前设置 html 的 font-size 值,不然会出现文字大小调动的情况。

rem 配合 flexible 插件

  • flexible 插件基准值(base)是设计图的 1/10

  • 使用 flexible

  1. 在 header 中引入 flexible.js 这个文件

  2. 根据设计图能够确定基准值, 配合 px2rem 插件 ,需要设置一个 rootFontSize

【案例:苏宁易购】

swiper 插件

Swiper 是纯 javascript 打造的滑动特效插件,面向手机、平板电脑等移动终端

swiper 中文网

other

a {
/* 取消链接高亮, 移动端特有的样式 */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

如同人类的的进化一样,CSS3 是 CSS2 的“进化”版本,在 CSS2 基础上,增强  或 新增  了许多特性, 弥补了 CSS2 的众多不足之处,使得 Web 开发变得更为高效和便捷。

现状

  • PC 端浏览器支持程度差,需要添加私有前缀
  • 移动端支持优于 PC 端
  • 不断改进中
  • 应用相对广泛

关于私有前缀:

在标准还未确定时,部分浏览器已经根据最初草案实现了部分功能,为了与之后确定下来的标准进行兼容,所以每种浏览器使用了自己的私有前缀与标准进行区分,当标准确立后,各大浏览器将逐步支持不带前缀的 css3 新属性

目前已有很多私有前缀可以不写了,但为了兼容老版本的浏览器,可以仍沿用私有前缀和标准方法,逐渐过渡

一般来说,CSS3 主要是为移动端而生的,因此我们在移动端没必要写太多的前缀,因为移动端的 ios 和 Android 的浏览器都是 webkit 内核

谷歌、苹果浏览器:-webkit-
火狐浏览器:-moz-
IE 浏览器:-ms-
欧朋浏览器:-o-

一般工作中不用去加,会通过打包工具 webpack 自动添加

选择器

阴影

  • text-shadow: 文字阴影
语法:text-shadow:none | <shadow> [ , <shadow> ]*
<shadow> => <length>{2,3} && <color>?
text-shadow:水平偏移 垂直偏移 羽化大小 颜色
水平偏移 垂直偏移 可以为负值,羽化大小可选且不可为负
可以设置多组阴影值,用逗号隔开
  • box-shadow: 边框阴影
语法:box-shadow:none | <shadow> [ , <shadow> ]*
<shadow> => inset? && <length>{2,4} && <color>?

box-shadow:水平偏移 垂直偏移 羽化大小 阴影外延 颜色
水平偏移、垂直偏移、阴影外延可以为负值,羽化大小、阴影外延可选,羽化大小不允许负值
可以设置多组阴影值,用逗号隔开
inset:设置对象的阴影类型为内阴影。该值为空时,则对象的阴影类型为外阴影

背景

background-size

bakground-clip

background-origin

渐变

线性渐变

linear-gradient() 指沿着某条直线朝一个方向产生的渐变效果

渐变实际上相当与一张图片,因为需要加给 background-image 才会生效

/* 最简单的渐变 颜色至少两个 方向默认从上到下 */
background-image: linear-gradient(red, green);

/* 设定渐变的方向 */
background-image: linear-gradient(to right, red, green);

/* 也可以设定渐变的角度 */
background-image: linear-gradient(45deg, red, green);

/* 设定渐变的范围 */
background-image: linear-gradient(to right, red 20%, green 80%)

/* 每一个区间表示渐变颜色的范围 */
background-image: linear-gradient(to right, red 20%, green 20%)

径向渐变

radial-gradient 指从一个中心点开始沿着四周产生渐变效果

/* 最简单的渐变 */
background-image: radial-gradient(red, green);

/* 指定圆的半径和圆心 */
background-image: radial-gradient(200px at center, red, green);

/* 指定椭圆 */
background-image: radial-gradient(200px 80px at center, red, green);

/* 指定范围 */
background-image: radial-gradient(200px at center, green 50%, red 50%);

盒子模型

CSS3 中可以通过 box-sizing 来指定盒模型,即可指定为 content-box、border-box,这样我们计算盒子大小的方式就发生了改变

可以分成两种情况:

  • box-sizing: border-box 计算方式为 content = width – border - padding
  • box-sizing: content-box 计算方式为 content = width

calc() 函数

用于动态计算长度值

  • 注意:运算符前后都需要保留一个空格,例如:width: calc(100% - 10px)
  • 任何长度值都可以使用 calc() 函数进行计算
  • calc() 函数支持 +-*/ 运算
  • calc() 函数使用标准的数学运算优先级规则

过渡

  • 过渡的属性

如果两个状态发生改变,没有过渡,效果是瞬间变化的,如果加上了过渡,那么这个过程就会有动画的效果,整个状态变化的过程是由浏览器来完成的,我们只需要关注开始状态与结束状态即可

/* transition-property:设置过渡属性 默认值为 all 表示全部*/
/* 多个用逗号分隔 */
transition-property: all;

/* transition-duration:设置过渡时间 */
transition-duration: 1s;

/* transition-delay:设置过渡延时 */
transition-delay: 2s;

/* transition-timing-function:设置过渡的速度 */
/* linear(匀速),ease(平滑),ease-in,ease-out,ease-in-out, steps(10)(分步动画) */
transition-timing-function: linear;

注意:

  1. 过渡必须要有两个状态的变化
  2. 过渡除了可以加到初始的状态,可以加到 hover 状态,但效果不一样,如果加到 hover 状态,回来就没有过渡了
  • 属性合写
/* 属性 时间 延时 速度 */
/* 多个过渡用逗号隔开 */
transition: width 1s 3s linear, border-radius 3s;

2D 转换

transform: 转换,是 CSS3 最具颠覆性的几个特性之一,既可以用于 2D 转换,也可以用于 3D 转换

transform: 2D 转换,元素在平面上实现移动、旋转、缩放、斜切等操作

scale 缩放

transform: scaleX(0.5); /* 让宽度变化 */
transform: scaleY(0.5); /* 让高度变化,注意不能写多个transform,不然会覆盖 */
transform: scale(0.5); /* 让宽度和高度同时变化 */

注意:

  • scale 接收的值是倍数,因此没有单位

  • scale 是一个值时,宽度高度会等比例同事缩放

  • scale 缩放时内部内容也会缩放

  • 可以通过 transition-origin 设定缩放原点 (可以是数值或方位词 top、left…)

translate 平移

transform: translateX(100px);
transform: translateY(100px);
transform: translate(100px, 100px);
transform: translate(50%, 50%);

注意:

  • translate 的值可以是 px,也可以是百分比,如果是百分比,那么参照的是自身的宽高
  • translate 移动的元素并不会影响其他盒子,类似于相对定位

rotate 旋转

transform: rotate(360deg); /* 旋转360度 */
transform: rotate(-360deg); /* 逆时针旋转360度 */

注意:

  • 单位是 deg,角度,不是 px
  • 正值顺时针转,负值逆时针转
  • 可以通过 transition-origin 设定旋转原点

rotate 旋转会让坐标轴也跟着旋转

skew 斜切(变形)

skew 在实际开发中,是用的最少的一个属性。一般来说,x 和 y 只会倾斜其中的一个

/* 在水平方向倾斜30deg */
transform: skewX(30deg);

/* 在垂直方向倾斜30deg */
transform: skewY(30deg);

【案例:扫光效果.html】

transform-origin 转换原点

通过 transform-origin 可以设置转换的中心原点

transform-origin: center center;
transform-origin: 40px 40px;

转换合写问题

transform 属性只能写一个,如果写了多个会覆盖,属性的值可以写多个, 用空格隔开即可

transform: translateX(800px) scale(1.5) rotate(360deg);
  • transform 属性可以连写,但是顺序对效果影响的,因为它会在第一个效果的基础上执行第二个效果,然后执行第三个效果(通常会把 rotate 放后面)
  • 如果对 transform 进行过度效果的时候,初始状态和结束状态要一一对应

【案例:盾牌打散与合并效果.html】

3D 转换

思考:2D 与 3D 的区别?

坐标轴

用 X、Y、Z 分别表示空间的 3 个维度,三条轴互相垂直。注意+Y 是向下的

perspective 透视

电脑显示屏是一个 2D 的平面,因为我们看不出来旋转的方向,通过 perspective 属性,可以定义 3D 元素距视图的距离,单位是 px。

说白了,设置了 perspective 属性后,就有了进大远小的效果了,在视觉上,让我们能看出来 3d 的效果。

注意:当为元素定义 perspective 属性时,其子元素会获得透视效果,而不是元素本身。

perspective500px;

对于我们眼睛来说,离我们越近的房子,我们会感觉到这个房子越大,离我们越远的房子,就会感觉越小,其实房子的大小都是一样的,只是在视觉上的一种不同。

rotate 旋转

transform: rotate(45deg); /* 让元素在平面2D中旋转,相当于沿着Z轴旋转 */
transform: rotateX(45deg); /* 让元素沿着X轴转45度 */
transform: rotateY(45deg); /* 让元素沿着Y轴转45度 */
transform: rotateZ(45deg); /* 让元素沿着Z轴转45度 */

【3D 旋转.html】

translate 平移

/* 沿着X轴的正方向移动45px */
transform: translateX(45px);
/* 沿着Y轴的正方向移动45px */
transform: translateY(45px);
/* 沿着Z轴的正方向移动45px */
transform: translateZ(45px);

【3D 平移.html】

【立方体.html】

transform-style

transform-style 属性规定如何在 3D 空间中呈现被嵌套的元素。注意这个属性只能给父元素添加

flat: 默认值,2d显示
preserve-3d: 3d显示

transform-style 与 perspective 区别

  • 透视:透视只是相当于设置了一个距离,辅助我们查看 3D 效果的工具
  • preserve-3d:给父盒子添加,让子元素保留 3D 的位置,说白了,只有设置了 preserve-3d,这个元素才能被称之为 3d 元素
  • 一个 3d 元素可以没有 perspective,但是不能没有 transform-style

【3D 导航案例.html】

【切割轮播图案例】

【3D 相册案例】

过渡结束事件

// 给最后一个ul添加过渡结束事件(节流阀)
uls[uls.length - 1].addEventListener('transitionend', function() {
isCanAnimate = true
})

动画

动画可以通过设置多个节点来精确控制一个或者一组动画,常用来实现复杂的动画效果

动画与过渡的区别:

过渡必须触发,需要两个状态的改变。
动画可以一直运行下去,不需要触发。实现效果与过渡差不多

使用一个动画的基本步骤:

1.通过 @keyframes 指定动画序列
2.通过百分比或者 from/to 将动画分割成多个节点
3.在各个节点中分别定义样式
4.通过 animation 将动画应用于相应的元素

animation

animation 是一个复合属性,一共有 8 个参数

animation-name: 动画名称,由@keyframes定义的
animation-duration: 动画的持续时间 默认0s
animation-timing-function: 动画的过渡类型 ease(默认) linear steps
animation-delay: 动画的延迟时间 默认0s
animation-iteration-count: 动画的循环次数 默认1次 infinite:无限循环
animation-direction: 设置动画在循环中的方向 normal:正向(默认) reverse(反向) alternate(往复循环)
animation-fill-mode: 设置动画结束时的状态 none:默认 backwards:动画结束时停留在开始状态 forwards: 动画结束时停留在结束的状态
animation-play-state: 设置动画的状态。running:运动(默认) paused:暂停

动画库的使用

https://daneden.github.io/animate.css/

字体图标

我们经常把网页常用的一些小的图标,做成精灵图,然后通过 background-position 去调整位置,但是这个需要引入图片,并且图片大小改变之后会失真。在 CSS3 中可以使用字体图片,即使用图标跟使用文字一样

优点:

1、将所有图标打包成字体库,减少请求

2、具有矢量性,可保证清晰度,可以修改文字的颜色或者样式

3、使用灵活,便于维护

阿里巴巴矢量图标:http://www.iconfont.cn/

Font Awesome 使用 http://fontawesome.dashgame.com/

弹性布局(伸缩布局)

布局:其实就是调整元素在水平和垂直方向上的布局方式

CSS3 在布局方面做了非常大的改进,使得我们对块级元素的布局排列变得十分灵活,适应性非常强,其强大的伸缩性,在响应式开中可以发挥极大的作用。

当给一个盒子设置了 display:flex 之后,这个盒子就有了 主轴侧轴 的概念
主轴:默认是水平方向向右,子元素在主轴上排列
侧轴:与主轴垂直的轴称作侧轴,默认是垂直方向向下

给容器设置的样式

  • flex-direction

用来调整主轴的方向,默认是水平方向,可选值有:

row:主轴方向为水平向右(默认)
column:主轴方向为竖直向下
row-reverse: 主轴方向为水平向左
column-reverse: 主轴方向是竖直向上
  • justify-content

用来设置子元素在 主轴方向的对齐方式 ,可选的值有:

flex-start: 弹性盒子元素将向起始位置对齐
flex-end: 弹性盒子元素将向结束位置对齐
center: 弹性盒子元素将向行中间位置对齐
space-between: 第一个贴左边,最后一个贴右边,其他盒子均分,保证每个盒子之间的空隙是相等的
space-around: 弹性盒子元素会平均地分布在行里(不会贴边)
  • align-items

用于调整 侧轴的对其方式 ,可选的值有:

flex-start:元素在侧轴的起始位置对其
flex-end:元素在侧轴的结束位置对其
center:元素在侧轴上居中对其
stretch:元素的高度会被拉伸到最大(不能给死高度)
  • flex-wrap

控制 flex 容器是单行或者多行,默认不换行

nowrap:不换行(默认),会压缩子盒子的宽度
wrap:当宽度不够的时候,会换行
  • align-content

用来设置多行时侧轴的排列方式

flex-start:各行向侧轴的起始位置堆叠
flex-end:各行向弹性盒容器的结束位置堆叠
center:各行向弹性盒容器的中间位置堆叠
space-between:第一行贴上边,最后一个行贴下边,其他行在弹性盒容器中平均分布
space-around:各行在侧轴中平均分布
stretch:拉伸,不设置高度的情况下

align-items 与 align-content 的区别

align-items 调整的是侧轴的对其方式,不换行一般用align-items
align-content: 必须是多行才生效,如果单行,没有效果。换行了就用 align-content

flex-flow 是以下属性的简写属性: flex-direction flex-wrap

flex 是以下属性的简写属性: flex-grow flex-shrink flex-basis

!> 上述属性都是给父盒子设置的,这些样式影响的是所有的子元素,接下来的几个属性是给子盒子设置的,用来单独设置子元素的样式

给子元素设置的样式

  • flex

用来设置子盒子如何分配主轴剩余空间

flex: 1;
  • order

定义项目的排列顺序。数值越小,排列越靠前,默认为 0。

order: 1;
  • align-self

align-self 用于设置当前元素在侧轴的位置,是给子元素设置,优先级比 align-items 的优先级高

取值与 align-items 的取值一样

阮一峰的博客http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

【案例:6 面神骰】

【案例:携程网】

【案例:360 浏览器】

other

微调元素

  • margin-top: - ;
  • transform: translateY();
  • position: relative; top: - ;

编码规范

Airbnb JavaScript Style Guide

Google JavaScript Style Guide

JavaScript Standard Style Guide

ESLint

JavaScript 语句后应该加分号么?

Vue + ESLint + Prettier

[vue 官方风格指南(https://cn.vuejs.org/v2/style-guide/)]

安装 node

https://nodejs.org/zh-cn/

配置 ESlint

$ npm install eslint -g
$ npm install eslint-plugin-html -g

$ eslint -v
$ eslint --init

# google 标准
# $ npm install eslint-config-google -g

# airbnb 标准
# $ npm install eslint-config-airbnb eslint-plugin-jsx-a11y eslint-plugin-import eslint-plugin-react -g

# standard 标准
$ npm install eslint-plugin-standard eslint-config-standard eslint-plugin-node eslint-plugin-promise -g

# vue
$ npm install eslint-plugin-vue -g

# es6 语法支持
$ npm install babel-eslint vue-eslint-parser -g

.eslintrc.json 文件

{
// plugin与extend的区别:extend提供的是eslint现有规则的一系列预设
// 而plugin则提供了除预设之外的自定义规则,当你在eslint的规则里找不到合适的的时候
"extends": ["google", "plugin: vue/essential"],
"plugins": ["html"],
"parserOptions": {
"sourceType": "module"
},
"rules": {
"valid-jsdoc": 2,
"require-jsdoc": 0,
"no-var": 0,
"vars-on-top": 0,
"eqeqeq": 2,
"space-before-function-paren": [2, "always"],
"semi": [2, "never"],
"comma-dangle": [2, "never"],
"linebreak-style": [2, "unix"],
"no-invalid-this": 0,
"max-len": 0,
"prefer-const": 0,
"arrow-parens": 0
}
}

{
"extends": ["standard", "plugin:vue/essential"],
// "extends": ["standard", "plugin:vue/recommended"],
"plugins": ["html"],
"parser": "vue-eslint-parser",
"parserOptions": {
"parser": "babel-eslint",
"ecmaVersion": 6,
"sourceType": "module"
},
"env": {
"browser": true,
"node": true
},
"rules": {
"no-new": 0,
"no-undef": 0,
"no-unused-vars": 1,
"space-before-function-paren": [2, "always"],
"eqeqeq": 0,
"handle-callback-err": 0,
"no-useless-escape": 0,
"new-cap": 0,
"vue/name-property-casing": 0 // vue
}
}

vscode 插件安装 ESLint

vscode 配置 User Settings

{
"javascript.validate.enable": false,
"typescript.validate.enable": false,
"eslint.nodePath": "C:\\Program Files\\nodejs\\node.exe",
"eslint.options": {
"configFile": "C:/Users/C/.vscode/.eslintrc.json"
},
"eslint.alwaysShowStatus": true,
"eslint.autoFixOnSave": true,
"eslint.validate": ["javascript", "javascriptreact", { "language": "html", "autoFix": true }, { "language": "vue", "autoFix": true }]
}

配置 prettier

$ npm install prettier -g
$ npm install eslint-plugin-prettier -g

vscode 插件安装 prettier

vscode 配置 User Settings

{
// 禁用默认html格式化
"html.format.enable": false,

"prettier.semi": false,
"prettier.singleQuote": true,
"prettier.jsxSingleQuote": true,
"prettier.eslintIntegration": true,
"prettier.htmlWhitespaceSensitivity": "ignore",
// 标签换行长度
"prettier.printWidth": 800,
"prettier.bracketSpacing": true
}

vuter

{
"vetur.format.defaultFormatter.js": "none",
// HTML Default Formatter
"vetur.format.defaultFormatter.html": "prettyhtml"
"vetur.format.defaultFormatterOptions": {
"prettyhtml": {
"printWidth": 1000,
"singleQuote": false,
"wrapAttributes": false,
"sortAttributes": false
}
}
}

配置 eslint 校验 typescript

npm install eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-alloy -g

https://github.com/AlloyTeam/eslint-config-alloy/

{
"extends": ["standard", "alloy", "alloy/typescript", "plugin:vue/essential"],
"plugins": ["html", "typescript"],
// "parser": "@typescript-eslint/parser",
"parserOptions": {
"parser": "@typescript-eslint/parser",
// "parser": "babel-eslint",
"ecmaVersion": 6,
"sourceType": "module"
},
"env": {
"browser": true,
"node": true,
"commonjs": true
},
"rules": {
"no-new": 0,
"no-undef": 0,
"no-unused-vars": 1,
"no-var": [0, "always"],
"space-before-function-paren": [2, "always"],
"typescript/class-name-casing": 2
}
}

ESLint 规则列表

.eslintrc.json 规则值:

"off"或者0    // 关闭规则关闭
"warn"或者1 // 在打开的规则作为警告(不影响退出代码)
"error"或者2 // 把规则作为一个错误(退出代码触发时为1

忽略检测警告

// 忽略检测下一行
/* eslint-disable-next-line */
// 忽略当前整个文件
/* eslint-disable */
// 忽略 no-new 规则
/* eslint-disable no-new */

规则列表 https://eslint.org/docs/rules/

"rules": {
"no-alert": 0,//禁止使用alert confirm prompt
"no-array-constructor": 2,//禁止使用数组构造器
"no-bitwise": 0,//禁止使用按位运算符
"no-caller": 1,//禁止使用arguments.caller或arguments.callee
"no-catch-shadow": 2,//禁止catch子句参数与外部作用域变量同名
"no-class-assign": 2,//禁止给类赋值
"no-cond-assign": 2,//禁止在条件表达式中使用赋值语句
"no-console": 2,//禁止使用console
"no-const-assign": 2,//禁止修改const声明的变量
"no-constant-condition": 2,//禁止在条件中使用常量表达式 if(true) if(1)
"no-continue": 0,//禁止使用continue
"no-control-regex": 2,//禁止在正则表达式中使用控制字符
"no-debugger": 2,//禁止使用debugger
"no-delete-var": 2,//不能对var声明的变量使用delete操作符
"no-div-regex": 1,//不能使用看起来像除法的正则表达式/=foo/
"no-dupe-keys": 2,//在创建对象字面量时不允许键重复 {a:1,a:1}
"no-dupe-args": 2,//函数参数不能重复
"no-duplicate-case": 2,//switch中的case标签不能重复
"no-else-return": 2,//如果if语句里面有return,后面不能跟else语句
"no-empty": 2,//块语句中的内容不能为空
"no-empty-character-class": 2,//正则表达式中的[]内容不能为空
"no-empty-label": 2,//禁止使用空label
"no-eq-null": 2,//禁止对null使用==或!=运算符
"no-eval": 1,//禁止使用eval
"no-ex-assign": 2,//禁止给catch语句中的异常参数赋值
"no-extend-native": 2,//禁止扩展native对象
"no-extra-bind": 2,//禁止不必要的函数绑定
"no-extra-boolean-cast": 2,//禁止不必要的bool转换
"no-extra-parens": 2,//禁止非必要的括号
"no-extra-semi": 2,//禁止多余的冒号
"no-fallthrough": 1,//禁止switch穿透
"no-floating-decimal": 2,//禁止省略浮点数中的0 .5 3.
"no-func-assign": 2,//禁止重复的函数声明
"no-implicit-coercion": 1,//禁止隐式转换
"no-implied-eval": 2,//禁止使用隐式eval
"no-inline-comments": 0,//禁止行内备注
"no-inner-declarations": [2, "functions"],//禁止在块语句中使用声明(变量或函数)
"no-invalid-regexp": 2,//禁止无效的正则表达式
"no-invalid-this": 2,//禁止无效的this,只能用在构造器,类,对象字面量
"no-irregular-whitespace": 2,//不能有不规则的空格
"no-iterator": 2,//禁止使用__iterator__ 属性
"no-label-var": 2,//label名不能与var声明的变量名相同
"no-labels": 2,//禁止标签声明
"no-lone-blocks": 2,//禁止不必要的嵌套块
"no-lonely-if": 2,//禁止else语句内只有if语句
"no-loop-func": 1,//禁止在循环中使用函数(如果没有引用外部变量不形成闭包就可以)
"no-mixed-requires": [0, false],//声明时不能混用声明类型
"no-mixed-spaces-and-tabs": [2, false],//禁止混用tab和空格
"linebreak-style": [0, "windows"],//换行风格
"no-multi-spaces": 1,//不能用多余的空格
"no-multi-str": 2,//字符串不能用\换行
"no-multiple-empty-lines": [1, {"max": 2}],//空行最多不能超过2行
"no-native-reassign": 2,//不能重写native对象
"no-negated-in-lhs": 2,//in 操作符的左边不能有!
"no-nested-ternary": 0,//禁止使用嵌套的三目运算
"no-new": 1,//禁止在使用new构造一个实例后不赋值
"no-new-func": 1,//禁止使用new Function
"no-new-object": 2,//禁止使用new Object()
"no-new-require": 2,//禁止使用new require
"no-new-wrappers": 2,//禁止使用new创建包装实例,new String new Boolean new Number
"no-obj-calls": 2,//不能调用内置的全局对象,比如Math() JSON()
"no-octal": 2,//禁止使用八进制数字
"no-octal-escape": 2,//禁止使用八进制转义序列
"no-param-reassign": 2,//禁止给参数重新赋值
"no-path-concat": 0,//node中不能使用__dirname或__filename做路径拼接
"no-plusplus": 0,//禁止使用++,--
"no-process-env": 0,//禁止使用process.env
"no-process-exit": 0,//禁止使用process.exit()
"no-proto": 2,//禁止使用__proto__属性
"no-redeclare": 2,//禁止重复声明变量
"no-regex-spaces": 2,//禁止在正则表达式字面量中使用多个空格 /foo bar/
"no-restricted-modules": 0,//如果禁用了指定模块,使用就会报错
"no-return-assign": 1,//return 语句中不能有赋值表达式
"no-script-url": 0,//禁止使用javascript:void(0)
"no-self-compare": 2,//不能比较自身
"no-sequences": 0,//禁止使用逗号运算符
"no-shadow": 2,//外部作用域中的变量不能与它所包含的作用域中的变量或参数同名
"no-shadow-restricted-names": 2,//严格模式中规定的限制标识符不能作为声明时的变量名使用
"no-spaced-func": 2,//函数调用时 函数名与()之间不能有空格
"no-sparse-arrays": 2,//禁止稀疏数组, [1,,2]
"no-sync": 0,//nodejs 禁止同步方法
"no-ternary": 0,//禁止使用三目运算符
"no-trailing-spaces": 1,//一行结束后面不要有空格
"no-this-before-super": 0,//在调用super()之前不能使用this或super
"no-throw-literal": 2,//禁止抛出字面量错误 throw "error";
"no-undef": 1,//不能有未定义的变量
"no-undef-init": 2,//变量初始化时不能直接给它赋值为undefined
"no-undefined": 2,//不能使用undefined
"no-unexpected-multiline": 2,//避免多行表达式
"no-underscore-dangle": 1,//标识符不能以_开头或结尾
"no-unneeded-ternary": 2,//禁止不必要的嵌套 var isYes = answer === 1 ? true : false;
"no-unreachable": 2,//不能有无法执行的代码
"no-unused-expressions": 2,//禁止无用的表达式
"no-unused-vars": [2, {"vars": "all", "args": "after-used"}],//不能有声明后未被使用的变量或参数
"no-use-before-define": 2,//未定义前不能使用
"no-useless-call": 2,//禁止不必要的call和apply
"no-void": 2,//禁用void操作符
"no-var": 0,//禁用var,用let和const代替
"no-warning-comments": [1, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],//不能有警告备注
"no-with": 2,//禁用with
"array-bracket-spacing": [2, "never"],//是否允许非空数组里面有多余的空格
"arrow-parens": 0,//箭头函数用小括号括起来
"arrow-spacing": 0,//=>的前/后括号
"accessor-pairs": 0,//在对象中使用getter/setter
"block-scoped-var": 0,//块语句中使用var
"brace-style": [1, "1tbs"],//大括号风格
"callback-return": 1,//避免多次调用回调什么的
"camelcase": 2,//强制驼峰法命名
"comma-dangle": [2, "never"],//对象字面量项尾不能有逗号
"comma-spacing": 0,//逗号前后的空格
"comma-style": [2, "last"],//逗号风格,换行时在行首还是行尾
"complexity": [0, 11],//循环复杂度
"computed-property-spacing": [0, "never"],//是否允许计算后的键名什么的
"consistent-return": 0,//return 后面是否允许省略
"consistent-this": [2, "that"],//this别名
"constructor-super": 0,//非派生类不能调用super,派生类必须调用super
"curly": [2, "all"],//必须使用 if(){} 中的{}
"default-case": 2,//switch语句最后必须有default
"dot-location": 0,//对象访问符的位置,换行的时候在行首还是行尾
"dot-notation": [0, { "allowKeywords": true }],//避免不必要的方括号
"eol-last": 0,//文件以单一的换行符结束
"eqeqeq": 2,//必须使用全等
"func-names": 0,//函数表达式必须有名字
"func-style": [0, "declaration"],//函数风格,规定只能使用函数声明/函数表达式
"generator-star-spacing": 0,//生成器函数*的前后空格
"guard-for-in": 0,//for in循环要用if语句过滤
"handle-callback-err": 0,//nodejs 处理错误
"id-length": 0,//变量名长度
"indent": [2, 4],//缩进风格
"init-declarations": 0,//声明时必须赋初值
"key-spacing": [0, { "beforeColon": false, "afterColon": true }],//对象字面量中冒号的前后空格
"lines-around-comment": 0,//行前/行后备注
"max-depth": [0, 4],//嵌套块深度
"max-len": [0, 80, 4],//字符串最大长度
"max-nested-callbacks": [0, 2],//回调嵌套深度
"max-params": [0, 3],//函数最多只能有3个参数
"max-statements": [0, 10],//函数内最多有几个声明
"new-cap": 2,//函数名首行大写必须使用new方式调用,首行小写必须用不带new方式调用
"new-parens": 2,//new时必须加小括号
"newline-after-var": 2,//变量声明后是否需要空一行
"object-curly-spacing": [0, "never"],//大括号内是否允许不必要的空格
"object-shorthand": 0,//强制对象字面量缩写语法
"one-var": 1,//连续声明
"operator-assignment": [0, "always"],//赋值运算符 += -=什么的
"operator-linebreak": [2, "after"],//换行时运算符在行尾还是行首
"padded-blocks": 0,//块语句内行首行尾是否要空行
"prefer-const": 0,//首选const
"prefer-spread": 0,//首选展开运算
"prefer-reflect": 0,//首选Reflect的方法
"quotes": [1, "single"],//引号类型 `` "" ''
"quote-props":[2, "always"],//对象字面量中的属性名是否强制双引号
"radix": 2,//parseInt必须指定第二个参数
"id-match": 0,//命名检测
"require-yield": 0,//生成器函数必须有yield
"semi": [2, "always"],//语句强制分号结尾
"semi-spacing": [0, {"before": false, "after": true}],//分号前后空格
"sort-vars": 0,//变量声明时排序
"space-after-keywords": [0, "always"],//关键字后面是否要空一格
"space-before-blocks": [0, "always"],//不以新行开始的块{前面要不要有空格
"space-before-function-paren": [0, "always"],//函数定义时括号前面要不要有空格
"space-in-parens": [0, "never"],//小括号里面要不要有空格
"space-infix-ops": 0,//中缀操作符周围要不要有空格
"space-return-throw-case": 2,//return throw case后面要不要加空格
"space-unary-ops": [0, { "words": true, "nonwords": false }],//一元运算符的前/后要不要加空格
"spaced-comment": 0,//注释风格要不要有空格什么的
"strict": 2,//使用严格模式
"use-isnan": 2,//禁止比较时使用NaN,只能用isNaN()
"valid-jsdoc": 0,//jsdoc规则
"valid-typeof": 2,//必须使用合法的typeof的值
"vars-on-top": 2,//var必须放在作用域顶部
"wrap-iife": [2, "inside"],//立即执行函数表达式的小括号风格
"wrap-regex": 0,//正则表达式字面量用小括号包起来
"yoda": [2, "never"]//禁止尤达条件
}

前言

我们使用 php 动态渲染页面时,有很多比较麻烦的地方。

  • 在前端写好页面以后,需要后台进行修改,意味这后端程序员也需要懂前端的知识,其实渲染的工作应该交给前端来做。
  • 前端没有写好页面的话,后端无法开始工作,需要等待前端的页面完成之后才能开始工作,拖延项目的进度。
  • 这种渲染,属于同步渲染,先获取数据, 如果数据获取的慢了, 会严重影响整个页面渲染速度, 且数据更新需要页面刷新

AJAX

即 Asynchronous [e’sɪŋkrənəs] Javascript And XML, AJAX 不是一门新的语言,而是对现有技术的综合利用。 本质是在 HTTP 协议的基础上以异步的方式与服务器进行通信

同步与异步

同步和异步概念:

同步:指的就是事情要一件一件做。等做完前一件才能做后一件任务

异步:不受当前任务的影响,两件事情同时进行,做一件事情时,不影响另一件事情的进行

编程中:异步程序代码执行时不会阻塞其它程序代码执行,从而提升整体执行效率

网页异步应用:

  1. 验证你的用户名是否已经存在(一边输入,一边获取你的信息,和后台比对)。
  2. 百度搜索提示,及相关内容展示(一边输入,一边找出了你可能要的内容)。
  3. 新浪微博评论(异步加载)。

XMLHttpRequest 可以以异步方式的请求数据处理程序, 可实现对网页的部分更新, 而不是刷新整个页面

XMLHttpRequest 对象

浏览器内建对象,用于与服务器通信(交换数据) , 由此我们便可实现对网页的部分更新,而不是刷新整个页面。这个请求是异步的,即在往服务器发送请求时,并不会阻碍程序的运行,浏览器会继续渲染后续的结构。

发送 get 请求

XMLHttpRequest 以异步的方式发送 HTTP 请求,因此在发送请求时,一样需要遵循 HTTP 协议。

使用 XMLHttpRequest 发送 get 请求的步骤

// 1. 创建一个 XMLHttpRequest 对象
var xhr = new XMLHttpRequest()

// 2. 设置请求行
// 第一个参数:请求方式 get/post
// 第二个参数:请求的地址 需要在url后面拼上参数列表
// 第三个参数:true 为异步,false为同步,默认为true,设为false没有意义
xhr.open('get', '01.php?name=zs')

// 3. 设置请求头(get不用设置)
// 请求头中可以设置 Content-Type,用以说明请求主体的内容是如何编码
// get 请求时没有请求体,无需设置请求头

// 4. 设置请求体
// get 请求的请求体为空,因为参数列表拼接到 url 后面了
xhr.send(null) // 参数为 null 或什么都不写

注意点 :

  • get 请求,设置请求行时,需要把参数列表拼接到 url 后面
  • get 请求不用设置请求头,不用说明请求主体的编码方式
  • get 请求的请求体为 null

发送 post 请求

// 1. 创建一个 XMLHttpRequest 对象
var xhr = new XMLHttpRequest()

// 2. 设置请求行 post请求的参数列表在请求体
xhr.open('post', '02.php')

// 3. 设置请求头, post 请求必须要设置 content-type, 标记请求体内容的解析方式
// 如果不设置请求头,请求能够发送出去,但是后端无法解析获取数据
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')

// 4. 设置请求体
xhr.send('name=Jepson&age=18')

注意点 :

  • post 请求,设置请求行时,不拼接参数列表
  • post 必须设置请求头中的 content-type 为 application/x-www-form-urlencoded, 标记请求体解析方式
  • post 请求需要将参数列表设置到请求体中

获取响应 readyState

readyState:记录了 XMLHttpRequest 对象的当前状态

readyState 有五种可能的值:

  • xhr.readyState = 0 时,UNSENT open 尚未调用
  • xhr.readyState = 1 时,OPENED open 已调用
  • xhr.readyState = 2 时,HEADERS_RECEIVED 接收到头信息
  • xhr.readyState = 3 时,LOADING 接收到响应主体
  • xhr.readyState = 4 时,DONE 响应完成

HTTP 响应分为 3 个部分,状态行、响应头、响应体。

// 给xhr注册一个 onreadystatechange 事件,当 xhr 的状态发生状态发生改变时,会触发这个事件。
// onreadystatechange 只会监听 2, 3, 4 的状态变化
xhr.onreadystatechange = function() {
console.log(xhr.readyState)
if (xhr.readyState == 4) {
//1. 获取状态行
console.log('状态行:' + xhr.status) // 成功返回 200
if (xhr.status == 200) {
//2. 获取响应头
console.log('所有的响应头:' + xhr.getAllResponseHeaders())
console.log('指定响应头:' + xhr.getResponseHeader('content-type'))
//3. 获取响应体
console.log(xhr.responseText)
}
}
}

案例

【判断用户名是否存在】

【用户登录案例】

【聊天机器人案例】

数据交互

浏览器端只是负责用户的交互和数据的收集以及展示,真正的数据都是存储在服务器端的。

我们现在通过 ajax 的确可以返回一些简单的数据(一个字符串),但是在实际开发过程中,肯定会会设计到大量的复杂类型的数据传输,比如数组、对象等,但是每个编程语言的语法都不一样。

因此我们会采用通过的数据交换格式( XMLJSON )来进行数据的交互。

XML(了解即可)

什么是 XML

  • XML 指可扩展标记语言(EXtensible Markup Language)
  • XML 是一种标记语言,很类似 HTML
  • XML 的设计宗旨是传输数据,而非显示数据
  • XML 标签没有被预定义。您需要自行定义标签。

语法规范

  • 第一行必须是版本信息
  • 必须有一个根元素(有且仅有一个)
  • 标签不可有空格、不可以数字或 . 开头、大小写敏感
  • 不可交叉嵌套,都是双标签,如果是单标签,必须闭合
  • 属性双引号(浏览器自动修正成双引号了)
  • 特殊符号要使用实体
  • 注释和 HTML 一样
<?xml version="1.0" encoding="utf-8" ?>
<students>
<student>
<name>张三</name>
<age>18</age>
<gender></gender>
<desc>路人甲</desc>
</student>
<student>
<name>李四</name>
<age>20</age>
<gender></gender>
<desc>路人乙</desc>
</student>
</students>

php 获取 xml 文件的内容

// 注意: 如果需要返回 xml 数据, 需要将 content-type 改成 text/xml, 不然浏览器以 text/html 解析
header( 'content-type:text/xml;charset=utf-8' );
// file_get_content 用于获取文件的内容
// 参数: 文件的路径
$result = file_get_content( "data.xml" );
echo $result;

js 解析 xml

// 获取服务端返回的 xml 数据,需要使用 xhr.responseXML,这是一个 document 对象,可以使用 DOM 中的方法查找元素。
var data = xhr.responseXML
// 获取所有的学生
var students = data.querySelectorAll('student')

缺点:虽然可以描述和传输复杂数据,但是其解析过于复杂, 并且体积较大,所以实现开发已经很少使用了

JSON 数据

JSON (JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript 规范,采用独立于编程语言的文本格式来存储和表示数据

  • 数据在键值对中
  • 数据由逗号分隔(最后一个 键值对不能带逗号)
  • 花括号保存对象,方括号保存数组
  • 键和值使用双引号
var obj = { a: 'Hello', b: 'World' } // 这是一个对象

// 这是一个 JSON 字符串,本质是一个字符串
var json = '{"a": "Hello", "b": "World"}'

JSON 数据在不同语言进行传输时,类型为字符串,不同的语言各自也都对应有解析方法,解析完成后就能很方便的使用了

php 处理 json

  • php 关联数组 ==> json ( json_encode )
// php的关联数组
$obj = array(
"a" => "hello",
"b" => "world",
"name" => "鹏鹏"
);
// json字符串
$json = json_encode( $obj );
echo $json;
  • json ==> php 对象/关联数组 ( json_decode )
$json = '{"a": "Hello", "b": "World"}'; // json字符串
// 第一个参数:json字符串
// 第二个参数:
// false,将json转换成对象(默认)
// true:将json转换成数组(推荐)
$obj = json_decode($json,true);
echo $obj['a'];

// 通过json文件获取到的内容就是一个json字符串。
$data = file_get_contents("data.json");
// 将json转换成数组
$result = json_decode($data, true);
print_r($result);

JS 处理 json

  • JSON.stringify(obj) :JS 对象 ==> JSON 字符串
var obj = { a: 'Hello', b: 'World' }
var result = JSON.stringify(obj) // '{"a": "Hello", "b": "World"}'
  • JSON.parse(obj) :JSON 字符串 ==> JS 对象
var json = '{"a": "Hello", "b": "World"}'
var obj = JSON.parse(json) // {a: 'Hello', b: 'World'}

【案例:获取表格数据.html】

兼容性处理 (了解, 不用处理)

现在一般最多兼容到 IE8, 这里以后见到了知道是在处理兼容性就行了

var xhr = null
if (XMLHttpRequest) {
//现代浏览器 IE7+
xhr = new XMLHttpRequest()
} else {
//老版本的 Internet Explorer (IE5 和 IE6)使用 ActiveX 对象:
xmlHttp = new ActiveXObject('Microsoft.XMLHTTP')
}

封装 ajax 工具函数

每次发送 ajax 请求,其实步骤都是一样的,重复了大量代码,我们完全可以封装成一个工具函数

//1. 创建xhr对象
//2. 设置请求行
//3. 设置请求头
//3. 设置请求体
//4. 监听响应状态
//5. 获取响应内容

参数提取

参数名 参数类型 描述 传值 默认值
type string 请求方式 get/post 只要不传 post,就是 get
url string 请求地址 接口地址 如果不传地址,不发送请求
async boolean 是否异步 true/fase 只要不传 false,那就是 true,异步请求
data object 请求数据 {key:value,key1:value2} 需要把这个对象拼接成参数的格式 uname=hucc&upass=12345
dataType string 返回的数据类型 xml/json/text text
success function 响应成功时调用 - -
error function 响应失败时调用 - -

参数检测

// 要求参数obj必须传递,否则直接不发送请求
if (!obj || typeof obj !== 'object') {
return
}
// 如果type传递的是post,那就发送post请求,否则发送get请求
var type = obj.type == 'post' ? 'post' : 'get'
var url = obj.url
if (!url) {
return
}
// 只有当async传递了false,才会发送同步请求,不然只发送异步请求
var async = obj.async == false ? false : true

完整版本

var $ = {
ajax: function(options) {
// 如果options参数没有传递,直接返回。
if (!options || typeof options !== 'object') {
return
}

// 处理默认参数
// 如果参数不是post,那就默认为get
var type = options.type === 'post' ? 'post' : 'get'
// 如果没有传url,直接返回
var url = option.url
if (!url) {
return
}
// 如果参数不是 false,那就默认是 true,发异步请求
var async = options.async == false ? false : true
// 把 option.data 对象中的数据拼接成键值对的字符串
var data = this.getData(options.data)

var xhr = new XMLHttpRequest()

// 设置请求行
// 如果是get请求,并且要上传参数,需要把参数拼接到url后面
if (type === 'get') {
url += '?' + data
data = null
}

xhr.open(type, url, async)

// 设置请求头
if (type === 'post') {
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
}
// 设置请求参数
xhr.send(data)

xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
//判断一下,如果dataType的值是json,就转成js对象.如果是xml,就返回dom对象,其他都是普通文本
if (options.dateType === 'json') {
var result = JSON.parse(xhr.responseText)
} else if (option.dataType === 'xml') {
var result = xhr.responseXML
} else {
var result = xhr.responseText
}
/*执行成功函数*/
options.success && options.success(result)
} else {
options.error && options.error()
}
}
}
},
getData: function(obj) {
// 将obj对象转换成参数
// 将对象转换成参数列表
if (!obj || typeof obj !== 'object') {
return null
}
var arr = []
for (var k in obj) {
arr.push(k + '=' + obj[k])
}
return arr.join('&')
}
}

【登录案例】

jQuery 中的 ajax 方法

jQuery 为我们提供了更强大的 Ajax 封装

$.ajax

参数列表

参数名称 描述 取值 示例
url 接口地址 url:”02.php”
type 请求方式 get/post type:”get”
timeout 超时时间 单位毫秒 timeout:5000
dataType 服务器返回的格式 json/xml/text(默认) dataType:”json”
data 发送的请求数据 对象 data:{name:”zs”, age:18}
beforeSend 调用前的回调函数 function(){} beforeSend:function(){ alert(1) }
success 成功的回调函数 function (data) {} success:function (data) {}
error 失败的回调函数 function (error) {} error:function(data) {}
complete 完成后的回调函数 function () {} complete:function () {}

使用示例:

$.ajax({
type: 'get', // 请求类型
url: '02.php', // 请求地址
data: { name: 'zs', age: 18 }, // 请求数据
dataType: 'json', // 希望接受的数据类型
timeout: 5000, // 设置超时时间
beforeSend: function() {
// alert("发送前调用");
// jq的ajax方法中beforeSend函数中如果执行了return false,那么请求就不发送了
},
success: function(res) {
// 如果有 dataType:"json",或后台有header(content-type: text/json),res就是已经转换好的js对象
// alert("成功时调用");
console.log(data)
},
error: function(error) {
// alert("失败时调用");
console.log(error)
},
complete: function() {
// alert("请求完成时调用"); // 不管成功失败都会执行
}
})

【案例:登录案例.html】

接口化开发

请求地址即所谓的接口,通常我们所说的接口化开发,其实是指一个接口对应一个功能, 并且严格约束了请求参数响应结果 的格式,这样前后端在开发过程中,可以减少不必要的讨论, 从而并行开发,可以极大的提升开发效率,另外一个好处,当网站进行改版后,服务端接口进行调整时,并不影响到前端的功能。

获取短信验证码

【案例:register】

需求文档(产品)

总需求:点击获取验证码按钮,向服务端发送请求, 调用服务器端短信接口, 服务器端根据传参, 调用第三方短信接口, 给手机发送验证码

需求1:格式校验
(1) 手机号码不能为空 如果为空提示"手机号不能为空"
(2) 手机号码格式必须正确, 提示"请输入正确的手机号码"

需求2:点击发送时,按钮显示为"发送中",并且不能重复提交请求

需求3:根据不同的响应结果,进行响应。
(1)如果接口调用成功
如果响应代码为100,倒计时
如果响应代码为101,提示手机号重复
(2)如果接口调用失败,告诉用户"服务器繁忙,请稍候再试"

接口文档

接口说明:获取短信验证码
接口地址:getCode.php
请求方式:get
接口传参:mobile 手机号
返回类型 json
接口返回:{
"code":"101",
"msg":"手机号码存在",
"mobile":"18511249258"
}
参数说明: code 当前业务逻辑的处理成功失败的标识 100:成功 101:手机号码存在
msg 当前系统返回给前端提示
mobile 当前的手机号码

注册接口

【案例:register】

表单序列化 serialize

jquery 提供了一个serialize()方法序列化表单,说白就是将表单中带有 name 属性的所有参数拼成一个格式为name=value&name1=value1这样的字符串。方便我们获取表单的数据。

// serialize 方法将表单参数序列化成一个字符串。必须指定 name 属性
// name=pp&pass=123456&repass=123456&mobile=15751776629&code=1234
$('form').serialize()

jquery 的 ajax 方法,data 参数能够直接识别表单序列化的数据

$.post({
url: 'register.php',
data: $('form').serialize(),
dataType: 'json',
success: function(info) {
console.log(info)
}
})

需求文档

注册功能
总需求:点击注册按钮,向服务端发送请求

需求1:表单校验
1.1 用户名不能为空,否则提示"请输入用户名"
1.2 密码不能为空,否则提示"请输入密码"
1.3 确认密码必须与密码一直,否则提示"确认密码与密码不一致"
1.4 手机号码不能为空,否则提示"请输入手机号码";
1.5 手机号码格式必须正确,否则提示"手机号格式错误"
1.6 短信验证码必须是4位的数字,否则提示"验证码格式错误"

需求2:点击注册按钮时,按钮显示为"注册中...",并且不能重复提交请求

需求3:根据不同响应结果,处理响应
3.1 接口调用成功
100 提示用户注册成功,3s后跳转到首页
101 提示用户"用户名已经存在"
102 提示用户"验证码错误"
3.2 接口调用失败,提示"服务器繁忙,请稍后再试",恢复按钮的值

接口文档

接口说明:注册
接口地址:register.php
请求方式:post
接口传参:name:用户名 pass:密码 code:验证码 mobile:手机号
返回类型 json
接口返回:{
"code":"100",
"msg":"注册成功",
"name":"Jepson"
}
参数说明:
code 当前业务逻辑的处理成功失败的标识 100:成功 101:用户存在 102:验证码错误
msg 当前系统返回给前端提示
name: 注册的用户名

模板引擎

是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的 HTML 文档。

为什么要使用模板引擎

我们通过 ajax 获取到数据后,需要把数据渲染到页面,在学习模板引擎前,我们的做法是大量的拼接字符串,对于结构简单的页面,这么做还行 ,但是如果页面结构很复杂,使用拼串的话代码可阅读性非常的差,而且非常容易出错,后期代码维护也是相当的麻烦。

总结来说拼串渲染两大缺点:

  1. js 中大量充斥着 html 结构拼串代码, 很冗余,可读性差
  2. 字符串拼接很麻烦, 且维护起来也很麻烦, 容易出错

常见的模板引擎

BaiduTemplate:http://tangram.baidu.com/BaiduTemplate/
velocity.js:https://github.com/shepherdwind/velocity.js/
ArtTemplate:https://github.com/aui/artTemplate

artTemplate 是使用最广泛,效率最高的模板引擎,需要大家掌握。

artTemplate

github 地址

中文 api 地址

artTemplate 的基本使用

1. 引入模板引擎的 js 文件

<script src='template-web.js'></script>

2. 准备模板

<!--
指定了type为text/html后,这一段script标签并不会解析,也不会显示。
-->
<script type="text/html" id="myTmp">
<p>姓名:隔壁老王</p>
<p>年龄:18</p>
<p>技能:查水表</p>
<p>描述:年轻力气壮</p>
</script>

3. 准备数据

//3. 准备数据,数据是后台获取的,可以随时变化
var json = {
userName: '隔壁老王',
age: 18,
skill: '查水表',
desc: '年轻气壮'
}

4. 将模板与数据进行绑定

//第一个参数:模板的id
//第二个参数:数据
//返回值:根据模板生成的字符串。
var html = template('myTmp', json)
console.log(html)

5. 修改模板

<script type="text/html" id="myTmp">
<p>姓名:{{userName}}</p>
<p>年龄:{{age}}</p>
<p>技能:{{skill}}</p>
<p>描述:{{desc}}</p>
</script>

6. 将数据显示到页面

var div = document.querySelector('div')
div.innerHTML = html

artTemplate 标准语法

if 语法

{{if gender='男'}}
<div class="man">
{{else}}
<div class="woman">
{{/if}}
</div>
</div>

each 语法

<!--
1. {{each data}} 可以通过$value 和 $index获取值和下标
2. {{each data v i}} 自己指定值为v,下标为i
-->
{{each data v i}}
<li>
<a href="{{v.url}}">
<img src="{{v.src}}" alt="" />
<p>{{v.content}}</p>
</a>
</li>
{{/each}}
//如果返回的数据是个数组,必须使用对象进行包裹,因为在{{}}中只写书写对象的属性。
var html = template('navTmp', { data: info })

瀑布流案例

封装 jQuery 瀑布流插件

// 特点分析:
// 1. 跟以前将的瀑布流不一样的是,这次的瀑布流固定版心为1200px
// 2. 瀑布流固定摆放5列,每一列的宽度固定为232px。
// 思路分析:
// 1. 计算每一列之间的缝隙
// 2. 初始化一个数组,用户存储每一列的高度 [0,0,0,0,0]
// 3. 查找数组的最小列,每次都把图片定位到最小列的位置
// 4. 更新数组最小列的高度(加上定位过来的图片的高度)

代码参考:

$.fn.waterfall = function() {
var $box = $(this)
var $item = $box.children()
var boxWidth = $box.width() //父盒子的宽度
var itemWidth = 232 //每个盒子固定宽度为232
var columns = 5 //固定摆放5列
var gap = (boxWidth - columns * itemWidth) / (columns - 1) //缝隙的宽度 10
var arr = [0, 0, 0, 0, 0] //初始化数组
$item.each(function() {
//查找最小列
var min = arr[0]
var minIndex = 0
for (var i = 0; i < arr.length; i++) {
if (min > arr[i]) {
min = arr[i]
minIndex = i
}
}
//设置位置
$(this).css({
left: minIndex * (itemWidth + gap),
top: min
})
//更新数组
arr[minIndex] = min + $(this).outerHeight() + gap
})
}

瀑布流完整版

// 需求分析:
// 1. 页面刚开始,没有任何一张图片。因此需要从通过ajax获取图片
// 2. 使用模版引擎将获取到的数据渲染到页面
// 3. 因为图片路径是从服务端获取的,加载需要时间,需要等待图片加载完成后才能使用瀑布流进行布局。
// 4. 给window注册scroll事件,当触底时,需要动态的加载图片。
// 5. 加载时,显示加载中的提示信息,并且要求不能重复发送ajax请求
// 6. 当服务端返回图片数量为0时,提示用户没有更多数据。

同源与跨域

同源

同源策略的基本概念

1995 年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。
同源策略:最初,它的含义是指,A 网页设置的 Cookie,B 网页不能打开,除非这两个网页”同源”。所谓”同源”指的是”三个相同”:协议相同、域名相同、端口相同

同源策略的目的

同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。

同源策略的限制范围

随着互联网的发展,“同源策略”越来越严格,目前,如果非同源,以下三种行为都将收到限制。

  1. Cookie、LocalStorage 和 IndexDB 无法读取
  2. DOM 无法获得
  3. AJAX 请求响应被拦截

虽然这些限制是很有必要的,但是也给我们日常开发带来不好的影响。比如实际开发过程中,往往都会把服务器端架设到一台甚至是一个集群的服务器中,把客户端页面放到另外一个单独的服务器。那么这时候就会出现不同源的情况,如果我们知道两个网站都是安全的话,我们是希望两个不同源的网站之间可以相互请求数据的。这就需要使用到 跨域

跨域

jsonp( 无兼容性问题 )

JSONP(JSON with Padding) 可用于解决主流浏览器的跨域数据访问的问题。

原理:服务端返回一个定义好的 js 函数的调用,并且将服务器的数据以该函数参数的形式传递过来,这个方法需要前后端配合

  • script  标签是不受同源策略的限制的,它可以载入任意地方的 JavaScript 文件。类似的还有imglink标签
jsonp 演化过程 1

php 文件

header("content-type:text/html;charset=utf-8");
echo "alert(1111)";

html 文件

<script src="http://www.api.com/testjs.php"></script>

原理:其实 src 的路径是什么文件不重要,无论引入 js 文件还是 php 文件,最后返回给浏览器的都是字符串,因此我们 script 标签是可以引入一个 php 文件的。

jsonp 演化过程 2

php 文件

header("content-type:text/html;charset=utf-8");
echo "var a = 118;";

html 文件

<script src="http://www.api.com/testjs.php"></script>
<script>
// a打印出来了118
console.log(a)
</script>

我们现在做到了一件事情,从不同源的 php 文件中获取到了数据

缺点:获取数据的 script 标签必须写在使用的 script 标签的前面,必须保证先有数据才能对数据进行渲染。

jsonp 演化过程 3

php 代码

header("content-type:text/html;charset=utf-8");
$arr = array(
"name"=>"zs",
"age"=>18
);
$result = json_encode($arr);
// 这是一段js函数的调用的代码,$result就是我们想要的数据
echo "func($result)";

js 代码

<script>
function func(data) {
console.log(data)
}
</script>
<script src="http://www.api.com/testjs.php"></script>

缺点:后端必须知道前端声明的方法的名字,后端才能调用。

jsonp 演化过程 4

php 代码

header("content-type:text/html;charset=utf-8");
$arr = array(
"name"=>"zs",
"age"=>18
);
$result = json_encode($arr);
// 这是一 段js函数的调用的代码,$result就是我们想要的数据
echo $_GET['callback']."($result)";

javascript 代码

function fun(data) {
console.log(data)
}
var button = document.querySelector('button')
button.onclick = function() {
var script = document.createElement('script')
script.src = 'http://www.api.com/testjs.php?callback=fun'
document.body.appendChild(script)
}
  1. jsonp 的原理就是 借助 script 标签 src 请求资源时,不受同源策略的限制
  2. 在服务端返回一个函数的调用,将数据作为当前调用函数的实参
  3. 在浏览器端,声明一个全局函数,通过形参就可以获取到服务端返回的对应的值

jquery 对于 jsonp 的封装

!> jsonp 仅支持 get 请求

// 使用起来相当的简单,跟普通的get请求没有任何的区别,只需要把 dataType 固定成 jsonp 即可
$.ajax({
type: 'get',
url: 'http://www.Jepson.com/testjs.php',
dataType: 'jsonp',
data: {
uname: 'zs',
upass: '123456'
},
success: function(info) {
console.log(info)
}
})

XMLHttpRequest2.0

XMLHttpRequest 是一个 javascript 内置对象,使得 Javascript 可以进行异步的 HTTP 通信。2008 年 2 月,就提出了 XMLHttpRequest Level 2 草案。

老版本的 XMLHttpRequest 的缺点:

  1. 仅支持传输文本数据,无法传输二进制文件,比如图片视频等。
  2. 传输数据时,没有进度信息,只能提示完成与否。
  3. 受到了”同源策略”的限制

新版本的功能:

  1. 可以设置 timeout 超时时间
  2. 可以使用 formData 对象管理表单数据
  3. 允许请求不同域名下的数据(跨域)
  4. 支持上传二进制文件
  5. 可以获取数据传输的进度信息

注意:我们现在使用 new XMLHttpRequest 创建的对象就是 2.0 对象了,我们之前学的是 1.0 的语法,现在学习一些 2.0 的新特性即可。

timeout 设置超时

xhr.timeout = 3000 // 设置超时时间
xhr.ontimeout = function() {
alert('请求超时')
}

formData 管理表单数据

formData 对象类似于 jquery 的 serialize 方法,序列化表单,实现表单的异步提交

!> 但 serialize 方法无法实现文件上传

使用:

  1. 实例化一个 formData 对象, new FormData(form); form 就是表单元素,DOM 对象
  2. formData 对象可以直接作为 xhr.send(formData) 的参数。注意此时数据是以二进制的形式进行传输。
  3. formData 有一个 append 方法,可以添加参数。formData.append(“id”, “1111”);
  4. 这种方式只能以 post 形式传递,不需要设置请求头,浏览器会自动为我们设置一个合适的请求头。

代码示例:

// 1. 使用formData必须发送post请求
xhr.open('post', '02-formData.php')

// 2. 获取表单元素
var form = document.querySelector('#myForm')
// 3. 创建form对象,可以直接作为send的参数。
var formData = new FormData(form)

// 4. formData可以使用append方法添加参数
formData.append('id', '1111')

// 5. 发送,不需要指定请求头,浏览器会自动选择合适的请求头
xhr.send(formData)

如果要获取 formData 中的数据,可以使用 formData.get('') 获取

文件上传

以前,文件上传需要借助表单进行上传,但是表单上传是同步的,也就是说文件上传时,页面需要提交和刷新,用户体验不友好,xhr2.0 中的 formData 对象支持文件的异步上传。

var formData = new FormData()
// 获取上传的文件,传递到后端
var file = document.getElementById('file').files[0]
console.dir(file)
formData.append('file', file)
xhr.send(formData)

$('#upload').on('change', function() {
// FormData 用于管理表单数据的
var form = document.querySelector('#form1')
var formData = new FormData(form)

// 发送给服务器
var xhr = new XMLHttpRequest()
xhr.open('post', 'upload.php')
xhr.send(formData) // 直接发送 formData

xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var r = xhr.responseText
}
}
})

// jquery
$('#upload').on('change', function() {
// 准备要上传的数据
var formData = new FormData()
// 如果 formData 中有文件对象了,就不需要再添加了
formData.append('file', this.files[0])
// 发送 AJAX 请求,上传文件
$.ajax({
url: 'upload.php',
contentType: false, // 设置编码类型
processData: false, // 设置传递值方式
data: formData,
type: 'post',
success: function(res) {
if (res.success) {
}
}
})
})

!> 如果使用 $.ajax 发送 , 需要添加如下两项参数
contentType: false, 设置编码类型
processData: false, 设置传递值方式

显示文件进度信息

xhr2.0 还支持获取上传文件的进度信息,因此我们可以根据进度信息可以实时的显示文件的上传进度。

  1. 需要注册 xhr.upload.onprogress = function(e){} 事件,用于监听文件上传的进度。注意:需要在 send 之前注册。
  2. 上传的进度信息会存储事件对象 e 中
  3. e.loaded 表示已上传的大小;e.total 表示整个文件的大小

代码参考:

xhr.upload.onprogress = function(e) {
inner.style.width = ((e.loaded / e.total) * 100).toFixed(2) + '%'
span.innerHTML = ((e.loaded / e.total) * 100).toFixed(2) + '%'
}
// toFixed(2) 保留两位小数

xhr.send(formData)

默认上传文件限制 8M,需要配置 php.ini,允许 php 上传大文件

跨域资源共享(CORS)

CORS 的使用

新版本的 XMLHttpRequest 对象,可以向不同域名的服务器发出 HTTP 请求。这叫做跨域资源共享(Cross-origin resource sharing,简称 CORS)。

跨域资源共享(CORS)的前提

  • 浏览器支持这个功能( 兼容性 IE10+ )
  • 服务器必须允许这种跨域

服务器允许跨域的代码:

// 允许所有的域名访问这个接口
header("Access-Control-Allow-Origin:*");
// 允许 www.abc.com 这个域名访问这个接口
header("Access-Control-Allow-Origin:http://www.abc.com");

CORS 的具体流程(了解)

  1. 浏览器发送跨域请求

  2. 服务器端收到一个跨域请求后,在响应头中添加 Access-Control-Allow-Origin Header 资源权限配置。发送响应

  3. 浏览器收到响应后,查看是否设置了header('Access-Control-Allow-Origin:请求源域名或者*');

    如果当前域已经得到授权,则将结果返回给浏览器,否则浏览器忽略此次响应

结论:

  1. 跨域行为是浏览器行为,响应是回来了, 只是浏览器安全机制做了限制, 对于跨域响应内容进行了忽略。
  2. 服务器与服务器之间是不存在跨域问题的

jsonp 与 cors 的对比

  • jsonp 兼容性好,老版本浏览器也支持,但是 jsonp 仅支持 get 请求,发送的数据量有限,使用麻烦
  • cors 需要浏览器支持 cors 功能才行。使用简单,只要服务端设置允许跨域,对于客户端来说,跟普通的 get、post 请求并没有什么区别
  • 跨域的安全性问题:因为跨域是需要服务端配合控制的 ,也就是说不论 jsonp 还是 cors,如果没有服务端的允许,浏览器是没法做到跨域的

【案例:图灵机器人】

沙箱模式

沙箱其实就是一个独立的环境,这个环境中任何的改变,都不会对外部环境产生影响

函数自调用一样,在自调用函数内部的变量是不会影响到外部的,因此函数自调用模式也叫沙箱模式

;(function(window) {
var fn = function() {
console.log('这是fn函数')
}
})(window)
  1. 代码写在自调用函数里面,减少全局污染
  2. 想要在外面使用 fn 函数,可将 fn 暴露到全局 window.fn = fn; 将 fn 函数的地址赋值给了 window 上的 fn 属性
  3. 一般,我们一个 js 文件只会暴露一个核心的功能(函数、方法): 目的还是为了减少全局污染

严格模式

  • 语法:'use strict'
  • 作用:让 js 引擎以更加严格的模式执行 js 代码
  • 最佳实践:在某个函数内部开启严格模式,而不是在全局环境中开启
  • 注意:
    • 严格模式只对当前作用域起作用
    • 应该在当前作用域最顶端使用use strict,否则严格模式无效
  • 使用严格模式好处:
    • 规范
    • 提高代码执行效率
// 严格模式应该配合沙箱模式一起使用。

// 沙箱模式 + 严格模式:
;(function() {
'use strict'

})()

严格模式规定

  • 变量必须显示声明
  • 函数参数不能重名
  • 禁止使用八进制
  • 不能使用保留字作为变量名称:implements, interface, let, package, private, protected, public, static, yield
  • 如果不符合上述规范,会直接报错

正则表达式

正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串(数据验证)、将匹配的子串替换(数据删除或替换)或者从某个串中取出符合某个条件的子串等(数据提取)

创建正则表达式

  • 构造函数的方式
// RegExp(regular expression)
var reg = new RegExp(/a/) // 匹配字母中有 a
  • 正则字面量
var reg = /a/

正则有 test 方法,作用是测试字符串是否符合正则表达式的规律,如果符合, 返回 true

console.log(reg.test('abc')) // true
console.log(reg.test('def')) // false

元字符

正则表达式由一些普通字符和元字符组成,普通字符包括大小写字母、数字等,而元字符则具有特殊的含义

常见元字符

\d 匹配一个数字字符。等价于 [0-9]

\D 匹配一个非数字字符。等价于 [^0-9]

\w 匹配包括下划线的任何单词字符。等价于[A-Za-z0-9_]

\W 匹配任何非单词字符。等价于 [^A-Za-z0-9_]

\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [\f\n\r\t\v]

\S 匹配任何非空白字符。等价于 [^\f\n\r\t\v]

\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, n 匹配字符 n\n 匹配换行符。\\ 匹配 \\( 则匹配 (

. 匹配除换行符 \n 之外的任何单字符。要匹配包括 ‘\n’ 在内的任何字符,可用(.|\n)

| 指明两项之间的一个选择。,优先级最低,| 的左右都是单独的整体

() 优先级最高,标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。使用 $0…$9 属性。要匹配这些字符,请使用 \(\) 。每个()就是一个子匹配 ‘\1’和’$1’用来指定第一个子匹配

/f|boot/ // 匹配 `f` 和 `boot`
/(f|b)oot/ // 匹配 `foot` 和 `boot`

空白字符

  • \f 匹配一个换页符
  • \n 匹配一个换行符
  • \r 匹配一个回车符
  • \t 匹配一个制表符
  • \v 匹配一个垂直制表符

字符类的元字符

  • [] 在正则表达式中表示 单个 字符的位置,[] 里面写这个位置可以出现的字符
;/[abc]/ // 匹配 a,b,c 任意一个字符
  • [^] 在中扩号中的 ^ 表示非的意思
// ^ 在方括号表达式开头中使用,此时它表示不接受该字符集合
;/[^abc]/ // 匹配除了a, b, c以外的其他字符
  • [a-z] [1-9]表示范围
;/[a-z]/ // 小写字母
;/[A-Z]/ // 大写字母
;/[0-9]/ // 数字
;/[a-zA-Z0-9]/ // 所有的小写字母和大写字母以及数字

边界类元字符

我们前面学习的正则只要有满足的条件的就会返回 true,并不能做到精确的匹配。

  • ^ 匹配输入字符串的开始位置

  • $ 匹配输入字符串的结尾位置

;/^chuan/ // 以chuan开头
;/chuan$/ // 以chuan结尾
;/^chuan$/ // 精确匹配 chuan

// 精确匹配chuan,表示必须是这个
console.log(/^chuan$/.test('chuanchuan')) // fasle

以后表单校验要精确匹配

  • \b 匹配一个字边界,即字与空格间的位置。如果它位于要匹配的字符串的开始,它在单词的开始处查找匹配项。如果它位于字符串的结尾,它在单词的结尾处查找匹配项。
    /\bCha/ : 匹配 Chapter 的开头三个字符
    /ter\b/ : 匹配 Chapter 的结尾三个字符
  • \B 表示非单词边界。位置并不重要,因为匹配不关心究竟是单词的开头还是结尾。
    /\Bapt/ 表达式匹配 Chapter 中的字符串 apt,但不匹配 aptitude 中的字符串 apt

量词类元字符

量词用来控制出现的次数,一般来说量词和边界会一起使用

  • * 匹配前面的子表达式零次或多次,等价于 {0,}
  • + 匹配前面的子表达式一次或多次,等价于 {1,}
  • ? 匹配前面的子表达式零次或一次,等价于 {0,1} 。当该字符紧跟在任何一个其他限制符 (*, +,?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串
  • {n} n 是一个非负整数。匹配确定的 n
  • {n,} n 是一个非负整数。至少匹配 n
  • {n,m} mn 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m
// {} 就近修饰单个字符
console.log(/chuan{2}/.test('chuanchuan')) // false
console.log(/(chuan){2}/.test('chuanchuan')) // true
console.log(/chuan{2}/.test('chuann')) // true

其他字符

  • g 全局标记,指定将该表达式应用到输入字符串中能够查找到的尽可能多的匹配
  • i 标记指定不区分大小写。表达式的结尾处
  • m 表明可以进行多行匹配,但是这个只有当使用^和$模式时才会起作用,在其他的模式中,加不加入 m 都可以进行多行匹配

优先级

从高到低的优先级顺序:

  1. \ 转义符
  2. (), (?:) , (?=), [] 圆括号和方括号
  3. *, + , ?, {n}, {n,}, {n,m} 限定符
  4. ^, $, \任何元字符、任何字符 定位点和序列(即:位置和顺序)
  5. | 替换,”或”操作

字符具有高于替换运算符的优先级,使得”m|food”匹配”m”或”food”。若要匹配”mood”或”food”,请使用括号创建子表达式,从而产生”(m|f)ood”。

正则的使用

字符串使用正则

  • replace()
var str = '   123AD  asadf   asadfasf  adf  '
// 1. 替换掉字符串中的所有空白
var str2 = str.replace(/\s/g, '') // g: global, 全局搜索
// 2. 将所有的ad替换成xx
var str2 = str.replace(/ad/g, 'xx')
// 3. 将所有的ad/AD替换成xx
var str2 = str.replace(/ad/gi, 'xx') // i: ignore 忽略大小写

var str = 'abc,efg,123,abc,123,a'
// 4. 所有的逗号替换成句号
var str2 = str.replace(/,/g, '。')

var jsonStr = '[{"name":"张三",score:80},{"name":"张三",score:90},{"name":"张三",score:81}]'
// 5. 把所有成绩都修改成100分
var str2 = jsonStr.replace(/\d{1,2}/g, '100')
  • match() ==> 匹配, 匹配符合正则表达式的字符
var str2 = 'zs的手机号是18938383838, ls的手机号13989907890, ww的手机号是13848962389,zl的手机号是18970890908'
// 需求: 匹配出来所有的手机号, 返回一个数组
var str3 = str2.match(/1[3-9]\d{9}/g)
console.log(str3)

正则的方法

  • test() ==> 测试字符串是否符合正则表达式的规律,符合,就返回 true

  • exec() ==> 提取,提取字符串中符合正则表达式的字符,需要用括号分组, 如果没有进行分组,返回的是符合整个正则表达式的字符

var str = '今天是2018-10-16,我这里的需求是提取出年月日'
// var reg = /\d{4}-\d{2}-\d{2}/; ==> 符合整个正则表达式的字符
var reg = /(\d{4})-(\d{2})-(\d{2})/ // ==> 有分组存在 ,默认组名为 undefined
var reg2 = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/ // ?<组名> 添加组名
var ret = reg.exec(str) // 提取出分组的内容以下标的形式存在返回的数组里面
var ret2 = reg2.exec(str)
console.log(ret)
console.log(ret2)
// index 代表 匹配到 ret 在 str 中的下标

实例

  • [xyz] 字符集合。匹配所包含的任意一个字符。例如, [abc] 可以匹配 “plain” 中的 ‘a’
  • [^xyz] 负值字符集合。匹配未包含的任意字符。例如, [^abc] 可以匹配 “plain” 中的’p’、’l’、’i’、’n’
  • [a-z] 匹配所有小写字母
  • [-a-z][a-z-] 匹配所有小写字母和 -
  • [A-Za-z0-9] 匹配任何大写字母小写字母和数字
  • \b([a-z]+)\1\b/gi 一个单词连续出现的位置
  • 将通用资源指示符 (URI) 分解为其组件
var str = 'https://www.baidu.com:80/index.html'
var patt1 = /(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/
arr = str.match(patt1)
for (var i = 0; i < arr.length; i++) {
document.write(arr[i])
document.write('<br>')
}
// https://www.baidu.com:80/index.html
// https
// www.baidu.com
// :80
// /index.html

后向引用

后向引用 正则表达式一个最重要的特性就是将匹配成功的模式的某部分进行存储供以后使用这一能力

对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 \n 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。

可以使用非捕获元字符 ?:?=?! 来忽略对这部分正则表达式的保存

?: 非获取匹配。匹配但不获取匹配结果,不存储供以后使用。这在使用 “或” 字符 (|) 来组合一个模式的各个部分是很有用。例如, industr(?:y|ies) 就是一个比 industry|industries 更简略的表达式

?= 正向预查。在任何匹配的字符串开始处匹配查找字符串。非获取匹配,不获取供以后使用。例如,’Windows (?=95|98|NT|2000)’ 能匹配 “Windows 2000” 中的 “Windows” ,但不能匹配 “Windows 3.1” 中的 “Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始

?! 负向预查,在任何不匹配的字符串开始处匹配查找字符串。非获取匹配,不获取供以后使用。例如’Windows (?!95|98|NT|2000)’ 能匹配 “Windows 3.1” 中的 “Windows”,但不能匹配 “Windows 2000” 中的 “Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始

后向引用一个最简单,最有用的应用是提供了确定文字中连续出现两个相同单词的位置的能力。请看下面的句子: Is is the cost of of gasoline going up up? 根据所写内容,上面的句子明显存在单词多次重复的问题。如果能有一种方法无需查找每个单词的重复现象就能修改该句子就好了。下面的 JScript 正则表达式使用一个子表达式就可以实现这一功能

var ss = 'Is is the cost of of gasoline going up up?'
var re = /\b([a-z]+) \1\b/gim
var rv = ss.replace(re, '$1')

在这个示例中,子表达式就是圆括号之间的每一项。所捕获的表达式包括一个或多个字母字符,即由[a-z]+所指定的。该正则表达式的第二部分是对前面所捕获的子匹配的引用,也就是由附加表达式所匹配的第二次出现的单词。\1用来指定第一个子匹配。单词边界元字符确保只检测单独的单词。如果不这样,则诸如 “is issued” 或 “this is” 这样的短语都会被该表达式不正确地识别。

插件

  • Sublime Tutor :键盘快捷方式教程
    Help > Sublime Tutor

  • AlignTab :自定义快捷键

快捷键

  • Ctrl + X 如果已经选中文本,则剪切该文本。如果未选中任何文本,则剪切光标所在行
  • Ctrl + Z 撤消
  • Ctrl + Shift + V 缩进粘贴
  • Ctrl + Shift + ZCtrl + Y 恢复
  • Ctrl + L Select line - Repeat to select next lines
  • Ctrl + D Select word - Repeat select others occurrences
  • Ctrl + Shift + D 如果已经选中文本,则复制该文本。如果未选中任何文本,则复制光标所在行
  • Ctrl + Enter Insert line after
  • Ctrl + Shift + Enter Insert line before
  • Alt + F3 选择所有相同单词的实例
  • TabCtrl + ] 缩进
  • Shift + TabCtrl + [ 取消缩进
  • Ctrl + Shift + K Delete Line
  • Ctrl + KK Delete from cursor to end of line
  • Ctrl + K + Backspace Delete from cursor to start of line
  • Alt + Shift + W 使用标签包裹选中部分
  • Ctrl + ← 移动光标至上一个词
  • Ctrl + → 移动光标至下一个词
  • Ctrl + Shift + ↓ Move line/selection down
  • Ctrl + Shift + ↑ Move line/selection up
  • Home 移动光标至行首
  • End 移动光标至行尾
  • Ctrl + Home 移动光标至文档开头
  • Ctrl + End 移动光标至文档结尾
  • Ctrl + M 跳转到左/右圆括号、方括号、大括号
  • Ctrl + Shift + M 选择括号内的内容
  • Ctrl + R 跳转到定义
  • Ctrl + / Comment/un-comment current line
  • Ctrl + Shift + / Block comment current selection
  • Ctrl + N 新建标签
  • Ctrl + PgUp 向左切换标签
  • Ctrl + PgDn 向右切换标签
  • Ctrl + W 关闭标签
  • Ctrl + Shift + T 重新打开标签
  • Shift + 鼠标右键 竖向选择
  • Ctrl + Shift + ' 选择与光标关联的开始和结束标签
  • Ctrl + Shift + A 选择容器内内容
  • Ctrl + Shift + ; 移除与你的光标相关的父标签(清除标记)
  • Ctrl + Shift + Y 计算数学表达式
  • Alt + ↓&↑ 以 0.1 的步长改变数字
  • Alt + Shift + ↓&↑ 以 10 的步长改变数字
  • Ctrl + ↓&↑ 以 1 的步长改变数字
  • Ctrl+K+U Ctrl+K+L 改变大小写

http://sublime.emptystack.net/

issues

“Error: 404 Not Found
Sorry, the requested URL ‘http://127.0.0.1:51004/view/29' caused an error:
‘buffer_id(29) is not valid (closed or unsupported file format)’
NOTE: If you run multiple instances of Sublime Text, you may want to adjust the server_port option in order to get this plugin work again.”

Quick Fix 1: Remove Strikethrough Extension

Sublime Text > Preferences > Package Settings > OmniMarkupPreviewer > Settings - User
paste the following to remove the strikeout package.

 {
'renderer_options-markdownrenderer': {
"extensions":["tables","fenced_code","codehilite"] ;
}
}

Quick Fix 2: Fix the Strikethrough Extension (if you need it)

Find the python-markdown sublime package.

/Packages/OmniMarkupPreviewer/OmniMarkupLib/Renderers/libs/mdx_strikeout.py

Replace the makeExtension() method with the following:

def makeExtension(*args, **kwargs):
return StrikeoutExtension(*args, **kwargs)
Save, quit and reload Sublime Text.

Markdown 基本语法

待…

Markdown 使用技巧

换行

  • 方法 1:连续两个以上空格+回车
  • 方法 2:使用 html 语言换行标签:<br>

居中

  • 使用 align 属性
  • 使用<center>标签(HTML5 不支持)

首行缩进两个字符

  • &nbsp; 不换行空格,全称 No-Break Space
  • &ensp; 半角的空格,全称是 En Space
  • &emsp; 全角的空格,全称是 Em Space,占据的宽度正好是 1 个中文宽度

字体

  • *斜体*或_斜体_
  • **粗体**
  • ***加粗斜体***
  • ~~删除线~~
  • 字号与颜色:使用内嵌 HTML
<font color="#0099ff" size="3" face="黑体">color=#0099ff size=3 face="黑体"</font>

效果:color=#0099ff size=3 face=”黑体”

背景色

使用内嵌 HTML 借助 table,tr,td 等表格标签的 bgcolor 属性

<table>
<tr><td bgcolor="orange">背景色是:orange</td></tr>
</table>

效果:

背景色是:orange

分割线

在一行中用三个以上的星号 * 、减号 - 、底线 _ 来建立一个分隔线,中间用空格隔开,行内不能有其他东西。(除第一个符号的左侧最多添加三个空格外三个相同符号两侧可以添加任意多个空格)

链接

文字

  • 行内式:[文字](url "title")
  • 参考式:[文字][1] [1]:url "title"
  • 自动链接:<url>,将链接用<>包起来,Markdown 会自动把它转成链接。

图片:

  • 行内式:![alt_text](url "title")

alt_text:图片的 alt 标签,用来描述图片的关键词,可以不写。最初的本意是当图片因为某种原因不能被显示时而出现的替代文字,后来又被用于 SEO,可以方便搜索引擎根据 alt_text 里面的关键词搜索到图片。 url:可以是图片的本地地址或者是网址。”title”:鼠标悬置于图片上会出现的标题文字,可以不写。

  • 参考式:同上

  • 使用 img 标签:<img src="" width="" height=""><div align=center></div> 实现居中

折叠按钮

<details>
<summary>
点击展开
</summary>
<!-- 内部展示内容 -->
</details>
点击展开

设置小三角样式:

summary::-webkit-details-marker {
color: #42b983;
}

Markdown 编辑器

typora