-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.json
1 lines (1 loc) · 168 KB
/
index.json
1
[{"uri":"/posts/play-canvas","tags":[],"content":"[toc] 前言 是 html5 出现 的 新 标签 , 像 所有 的 dom 对象 一样 它 有 自己 本身 的 属性 、 方法 和 事件 , 其中 就 有 绘图 的 方法 ,js 能够 调用 它 来 进行 绘图 , 最近 在 研读 《html5 与 css3 权威 指南 》 下面 对 其中 最 好玩 的 canvas 的 学习 做 下 读书笔记 与 实验 。 温馨 提示 : 以下 所有 实验 请 使用 最新版 的 opera 基本知识 context: 一直 觉得 这个 翻译成 “ 上下文 ” 真够 蛋 疼 的 ,context 是 一个 封装 了 很多 绘图 功能 的 对象 , 获取 这个 对象 的 方法 是 var context =canvas.getContext(\"2d\"); 也许 这个 2d 勾起 了 大家 的 无限 遐想 , 但是 很 遗憾 的 告诉 你 html5 还 只是 个 少女 , 不 提供 3d 服务 。 > canvas 元素 绘制 图像 的 时候 有 两种 方法 , 分别 是 : context.fill()// 填充 context.stroke()// 绘制 边框 style: 在 进行 图形 绘制 前 , 要 设置 好 绘图 的 样式 context.fillStyle// 填充 的 样式 context.strokeStyle// 边框 样式 context.lineWidth// 图形 边框 宽度 > 颜色 的 表示 方式 : 直接 用 颜色 名称 :\"red\" \"green\" \"blue\" 十六进制 颜色 值 : \"#EEEEFF\" rgb(1-255,1-255,1-255) rgba(1-255,1-255,1-255, 透明度 ) 和 GDI 是 如此 的 相像 , 所以 用 过 GDI 的 朋友 应该 很快 就 能 上 手 # 绘制 矩形 context.fillRect(x,y,width,height) strokeRect(x,y,width,height) x: 矩形 起点 横坐标 ( 坐标 原点 为 canvas 的 左上角 , 当然 确切 的 来说 是 原始 原点 , 后面 写 到 变形 的 时候 你 就 懂 了 , 现在 暂时 不用 关系 ) y: 矩形 起点 纵坐标 width: 矩形 长度 height: 矩形 高度 function draw21(id) { var canvas = document.getElementById(id) if (canvas == null) return false; var context = canvas.getContext(\"2d\"); // 实践 表明 在 不 设施 fillStyle 下 的 默认 fillStyle=black context.fillRect(0, 0, 100, 100); // 实践 表明 在 不 设施 strokeStyle 下 的 默认 strokeStyle=black context.strokeRect(120, 0, 100, 100); // 设置 纯色 context.fillStyle = \"red\"; context.strokeStyle = \"blue\"; context.fillRect(0, 120, 100, 100); context.strokeRect(120, 120, 100, 100); // 设置 透明度 实践证明 透明度 值 >0,=1 时 为 纯色 , 值 0,=1 时 为 纯色 , 值 <=0 时 为 完全 透明 context.fillStyle = \"rgba(255,0,0,0.2)\"; context.strokeStyle = \"rgba(255,0,0,0.2)\"; context.fillRect(240, 0, 100, 100); context.strokeRect(240, 120, 100, 100); context.clearRect(50, 50, 240, 120); } 圆弧 context.arc(x, y, radius, starAngle,endAngle, anticlockwise)x: 圆心 的 x 坐标 y: 圆心 的 y 坐标 straAngle: 开始 角度 endAngle: 结束 角度 anticlockwise: 是否 逆时针 (true) 为 逆时针 ,(false) 为 顺时针 ps: 经过 试验 证明 书本上 ture 是 顺时针 ,false 是 逆时针 是 错误 的 , 而且 无论是 逆时针 还是 顺时针 , 角度 都 沿着 顺时针 扩大 , 如下 图 :function draw0(id) { var canvas = document.getElementById(id); if (canvas == null) { return false; } var context = canvas.getContext('2d'); context.beginPath(); context.arc(200, 150, 100, 0, Math.PI * 2, true); // 不 关闭 路径 路径 会 一直 保留 下去 , 当然 也 可以 利用 这个 特点 做出 意想不到 的 效果 context.closePath(); context.fillStyle = 'rgba(0,255,0,0.25)'; context.fill(); } 一不小心 画 了 小 日本 的 国旗 ... 赶紧 调 下 颜色 和 大小 , 绿色 倒 是 挺 合适 的 ~ 路径 context.beginPath() context.closePath() 细心 的 朋友 会 发现 上面 的 画圆 并 不单单是 直接 用 arc 还 用到 了 context 的 beginPath 和 closePath 方法 , 参考书 不愧 是 参考书 , 例子 给 得 太 简单 了 , 实话 说 一 开始 我 凌乱 了 , 耐心 下来 做 了 几个 实验 才 舒缓 蛋 疼 的 心情 实验 代码 如下 , 通过 分别 注释 closePath 和 beginPath 看 fill stoke 和 fill stroke 结合 下 画 出来 的 两个 1/4 弧线 达到 实验 效果 function draw23(id) { var canvas = document.getElementById(id); if (canvas == null) { return false; } var context = canvas.getContext('2d'); var n = 0; // 左侧 1/4 圆弧 context.beginPath(); context.arc(100, 150, 50, 0, Math.PI/2 , false); context.fillStyle = 'rgba(255,0,0,0.25)'; context.fill(); context.strokeStyle = 'rgba(255,0,0,0.25)' context.closePath(); context.stroke(); // 右侧 1/4 圆弧 context.beginPath(); context.arc(300, 150, 50, 0, Math.PI/2 , false); context.fillStyle = 'rgba(255,0,0,0.25)'; context.fill(); context.strokeStyle = 'rgba(255,0,0,0.25)'; context.closePath(); context.stroke(); } 得出 的 结论 有 :* 号 为 重点 1、 系统 默认 在 绘制 第一个 路径 的 开始 点 为 beginPath 2、 如果 画 完 前面 的 路径 没有 重新 指定 beginPath, 那么 画 第 其他 路径 的 时候 会 将 前面 最近 指定 的 beginPath 后 的 全部 路径 重新 绘制 3、 每次 调用 context.fill() 的 时候 会 自动 把 当 次 绘制 的 路径 的 开始 点 和 结束 点 相连 , 接着 填充 封闭 的 部分 ps: 书本 的 结论 是 如果 没有 closePath 那么 前面 的 路 劲 会 保留 , 实验 证明 正确 的 结论 是 如果 没有 重新 beginPath 那么 前面 的 路 劲 会 保留 ps1: 如果 你 真心 凌乱 了 , 那么 记住 每次 画 路径 都 在 前后 加 context.beginPath() 和 context.closePath() 就 行 绘制 线段 context.moveTo(x,y) context.lineTo(x,y) x:x 坐标 y:y 坐标 每次 画线 都 从 moveTo 的 点 到 lineTo 的 点 , 如果 没有 moveTo 那么 第一次 lineTo 的 效果 和 moveTo 一样 , 每次 lineTo 后 如果 没有 moveTo, 那么 下次 lineTo 的 开始 点 为 前 一次 lineTo 的 结束 点 function draw8(id) { var canvas = document.getElementById(id); if (canvas == null) return false; var context = canvas.getContext(\"2d\"); //context.beginPath(); context.strokeStyle = \"rgb(250,0,0)\"; context.fillStyle = \"rgb(250,0,0)\" // 实验 证明 第一次 lineTo 的 时候 和 moveTo 功能 一样 context.lineTo(100, 100); // 之后 的 lineTo 会 以上 次 lineTo 的 节点 为 开始 context.lineTo(200, 200); context.lineTo(200, 100); context.moveTo(200, 50); context.lineTo(100,50); context.stroke(); } 下面 给出 书本 的 例子 , 一朵 绿色 的 菊花 , 涉及 数学 , 不 多 解析 , 有 兴趣 的 自己 研究 function draw1(id) { var canvas = document.getElementById(id); if (canvas == null) return false; var context = canvas.getContext(\"2d\"); context.fillStyle = \"#EEEEFF\"; context.fillRect(0, 0, 400, 300); var n = 0; var dx = 150; var dy = 150; var s = 100; context.beginPath(); context.fillStyle = 'rgb(100,255,100)'; context.strokeStyle = 'rgb(0,0,100)'; var x = Math.sin(0); var y = Math.cos(0); var dig = Math.PI / 15 * 11; for (var i = 0; i < 30; i++) { var x = Math.sin(i * dig); var y = Math.cos(i * dig); context.lineTo(dx + x * s, dy + y * s); } context.closePath(); context.fill(); context.stroke(); } 绘制 贝塞尔 曲线 ( 贝济埃 、bezier) context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y) 绘制 二次 样条 曲线 context.quadraticCurveTo(qcpx,qcpy,qx,qy)cp1x: 第一个 控制点 x 坐标 cp1y: 第一个 控制点 y 坐标 cp2x: 第二个 控制点 x 坐标 cp2y: 第二个 控制点 y 坐标 x: 终点 x 坐标 y: 终点 y 坐标 qcpx: 二次 样条 曲线 控制点 x 坐标 qcpy: 二次 样条 曲线 控制点 y 坐标 qx: 二次 样条 曲线 终点 x 坐标 qy: 二次 样条 曲线 终点 y 坐标 function draw24(id) { var canvas = document.getElementById(id); if (canvas == null) { return false; } var context = canvas.getContext(\"2d\"); context.moveTo(50, 50); context.bezierCurveTo(50, 50,150, 50, 150, 150); context.stroke(); context.quadraticCurveTo(150, 250, 250, 250); context.stroke(); } 下面 给出 书本 的 例子 , 一朵 扭曲 的 绿色 菊花 ... 编书 这 哥们 对 菊花 情有独钟 啊 - -function draw2(id) { var canvas = document.getElementById(id); if (canvas == null) { return false; } var context = canvas.getContext(\"2d\"); context.fillStyle = \"#EEEFF\"; context.fillRect(0, 0, 400, 300); var n = 0; var dx = 150; var dy = 150; var s = 100; context.beginPath(); context.globalCompositeOperation = 'and'; context.fillStyle = 'rgb(100,255,100)'; var x = Math.sin(0); var y = Math.cos(0); var dig = Math.PI / 15 * 11; context.moveTo(dx, dy); for (var i = 0; i < 30; i++) { var x = Math.sin(i * dig); var y = Math.cos(i * dig); context.bezierCurveTo(dx + x * s, dy + y * s - 100, dx + x * s + 100, dy + y * s, dx + x * s, dy + y * s); } context.closePath(); context.fill(); context.stroke(); } 关于 贝塞尔 曲线 可以 参考 百度 百科 和 http://blog.csdn.net/zhangci226/article/details/4018449 这 篇文章 线性 渐变 var lg= context.createLinearGradient(xStart,yStart,xEnd,yEnd), 线性 渐变 颜色 lg.addColorStop(offset,color)xstart: 渐变 开始 点 x 坐标 ystart: 渐变 开始 点 y 坐标 xEnd: 渐变 结束 点 x 坐标 yEnd: 渐变 结束 点 y 坐标 offset: 设定 的 颜色 离 渐变 结束 点 的 偏移量 (0~1)color: 绘制 时 要 使用 的 颜色 给出 书本 偏移量 的 解析 图 , 从 图 可以 看出 线性 渐变 可以 是 两种 以上 颜色 的 渐变 function draw25(id) { var canvas = document.getElementById(id); if (canvas == null) return false; var context = canvas.getContext('2d'); var g1 = context.createLinearGradient(0, 0, 0, 300); g1.addColorStop(0, 'rgb(255,0,0)'); // 红 g1.addColorStop(0.5, 'rgb(0,255,0)');// 绿 g1.addColorStop(1, 'rgb(0,0,255)'); // 蓝 // 可以 把 lg 对象 理解 成 GDI 中 线性 brush context.fillStyle = g1; // 再 用 这个 brush 来 画 正方形 context.fillRect(0, 0, 400, 300); } 径向 渐变 ( 发散 )var rg=context.createRadialGradient(xStart,yStart,radiusStart,xEnd,yEnd,radiusEnd) 径向 渐变 ( 发散 ) 颜色 rg.addColorStop(offset,color) xStart: 发散 开始 圆心 x 坐标 yStart: 发散 开始 圆心 y 坐标 radiusStart: 发散 开始 圆 的 半径 xEnd: 发散 结束 圆心 的 x 坐标 yEnd: 发散 结束 圆心 的 y 坐标 radiusEnd: 发散 结束 圆 的 半径 offset: 设定 的 颜色 离 渐变 结束 点 的 偏移量 (0~1) color: 绘制 时 要 使用 的 颜色 书本 并 没有 给出 发散 偏移量 的 图 , 特地 画 了 幅 : 下面 给出 两个 实验 function draw26(id) { // 同一个 圆心 画 球型 /*var canvas = document.getElementById(id); if (canvas == null) return false; var context = canvas.getContext('2d'); var g1 = context.createRadialGradient(200, 150, 0, 200, 150, 100); g1.addColorStop(0.1, 'rgb(255,0,0)'); g1.addColorStop(1, 'rgb(50,0,0)'); context.fillStyle = g1; context.beginPath(); context.arc(200, 150, 100, 0, Math.PI * 2, true); context.closePath(); context.fill();*/ // 不同 圆心 看 径向 渐变 模型 var canvas = document.getElementById(id); if (canvas == null) return false; var context = canvas.getContext('2d'); var g1 = context.createRadialGradient(100, 150, 10, 300, 150, 50); g1.addColorStop(0.1, 'rgb(255,0,0)'); g1.addColorStop(0.5, 'rgb(0,255,0)'); g1.addColorStop(1, 'rgb(0,0,255)'); context.fillStyle = g1; context.fillRect(0, 0, 400, 300); } 图形 变形 1、 平移 context.translate(x,y) x: 坐标 原点 向 x 轴 方向 平移 x y: 坐标 原点 向 y 轴 方向 平移 y2、 缩放 context.scale(x,y) x:x 坐标轴 按 x 比例 缩放 y:y 坐标轴 按 y 比例 缩放 3、 旋转 context.rotate(angle) angle: 坐标轴 旋转 x 角度 ( 角度 变化 模型 和 画圆 的 模型 一样 )function draw5(id) { var canvas = document.getElementById(id); if (canvas == null) return false; var context = canvas.getContext(\"2d\"); context.save(); // 保存 了 当前 context 的 状态 context.fillStyle = \"#EEEEFF\"; context.fillRect(0, 0, 400, 300); context.fillStyle = \"rgba(255,0,0,0.1)\"; // 平移 缩放 旋转 1 2 3 context.translate(100, 100); context.scale(0.5, 0.5); context.rotate(Math.PI / 4); context.fillRect(0, 0, 100, 100); context.restore(); // 恢复 到 刚刚 保存 的 状态 , 保存 恢复 只能 使用 一次 context.save(); // 保存 了 当前 context 的 状态 context.fillStyle = \"rgba(255,0,0,0.2)\"; // 平移 旋转 缩放 1 3 2 context.translate(100, 100); context.rotate(Math.PI / 4); context.scale(0.5, 0.5); context.fillRect(0, 0, 100, 100); context.restore(); // 恢复 到 刚刚 保存 的 状态 context.save(); // 保存 了 当前 context 的 状态 context.fillStyle = \"rgba(255,0,0,0.3)\"; // 缩放 平移 旋转 2 1 3 context.scale(0.5, 0.5); context.translate(100, 100); context.rotate(Math.PI / 4); context.fillRect(0, 0, 100, 100); context.restore(); // 恢复 到 刚刚 保存 的 状态 context.save(); // 保存 了 当前 context 的 状态 context.fillStyle = \"rgba(255,0,0,0.4)\"; // 缩放 旋转 平移 2 3 1 context.scale(0.5, 0.5); context.rotate(Math.PI / 4); context.translate(100, 100); context.fillRect(0, 0, 100, 100); context.restore(); // 恢复 到 刚刚 保存 的 状态 context.save(); // 保存 了 当前 context 的 状态 context.fillStyle = \"rgba(255,0,0,0.5)\"; // 旋转 平移 缩放 3 1 2 context.rotate(Math.PI / 4); context.translate(100, 100); context.scale(0.5, 0.5); context.fillRect(0, 0, 100, 100); context.restore(); // 恢复 到 刚刚 保存 的 状态 context.save(); // 保存 了 当前 context 的 状态 context.fillStyle = \"rgba(255,0,0,1)\"; // 旋转 缩放 平移 3 2 1 context.rotate(Math.PI / 4); context.scale(0.5, 0.5); context.translate(100, 100); context.fillRect(0, 0, 100, 100); // 实验 表明 应该 移动 的 是 坐标轴 // 实验 表明 缩放 的 是 坐标轴 比例 // 实验 表明 旋转 的 是 坐标轴 // 综合 上述 , 因此 平移 缩放 旋转 三者 的 顺序 不同 都 将 画 出 不同 的 结果 } 由于 ( 平移 , 缩放 , 旋转 ) 和 ( 平移 , 旋转 , 缩放 ) 一样 ( 缩放 , 选装 , 平移 ) 和 ( 旋转 , 缩放 , 平移 ) 一样 所以 实验 结果 只能 看到 “4” 中 情况 , 其实 是 有 两种 情况 被 覆盖 了 下面 给出 平移 , 缩放 , 旋转 先后顺序 不同 , 坐标轴 的 变化 图 ","title":" 玩转 canvas","oriTitle":"玩转canvas"},{"uri":"/posts/react-router-link-3way","tags":["React"],"content":" 通过 `` 跳转 通过 `` 进行 导航 import { Redirect } form 'react-router'Class Login extends React.Component{ render(){ const {loginSucess} = this.props; if(loginSucess){ return () } }}BrowserRouter 路由 模式 跳转 this.props.history.push(/Article/${id});HashRouter 路由 模式 跳转 window.location.href='/#/newLink';","title":"react-router4 跳转 链接 方式 汇总 ","oriTitle":"react-router4 跳转链接方式汇总"},{"uri":"/posts/seajs-learn","tags":["seajs"],"content":" 疑难 seajs 加载 jquery 时 提示 $ is not a function 该 怎么 解决 if (typeof define === \"function\" && (define.amd)) { define( \"jquery\", [], function() { return jQuery; }); } 改成 if (typeof define === \"function\" && (define.amd || define.cmd)) { define( \"jquery\", [], function() { return jQuery; }); } 或 if (typeof define === \"function\") { define( \"jquery\", [], function() { return jQuery; }); }seajs 载入 jquery 插件 -- 需 插件 模块化 define(function(require){ return function(jQuery){ //put plugin code here ... }})seajs 载入 js 文件 -- 需 包装 成 cmd 模块 define(function(requre,exports,module){ var $ = require('jquery'); require(\"fullpage\")($) ////jquery plugin module use $(function(){ $(\"#jlhomecontainer\").fullpage({ 'navigation': true, 'slideSelector': '.slide', 'continuousHorizontal': true, }) })})map//map 支持 正则 匹配 , 批量 载入 多个 文件 seajs.config({map:[[/^(.\\.(?:css|js))(.)$/i, '$1?v=1.7941']]})","title":"seajs 学习 整理 ","oriTitle":"seajs 学习整理"},{"uri":"/posts/server-mongodb_mongoose-person-setting","tags":["mongoDB"],"content":" 连接 mongodbvar mongoose = require('mongoose');mongoose.connect('mongodb://admin:password@host:port/dbname');//testconnectionString = 'mongodb://localhost/Node-tao', 定义 一个 schemanew Schema({..}, options);###Note that if the resulting record is converted to an object or JSON, virtuals are not included by default. Passvirtuals : true to either toObject() or to toJSON() to have them returned.// 虚拟 属性 开关 ,true: 支持 var ContentSchema = new mongoose.Schema({ name:String, // 定义 一个 属性 name, 类型 为 String updateDate: { type: Date, default: Date.now } },{toJSON:{virtuals: true}});// 定义 虚拟 属性 ContentSchema.virtual('created_day').get(function() { return moment(this.updateDate).format('YYYY-MM-DD');})Sub Docs var ChildSchema1 = new Schema({name:String}); var ChildSchema2 = new Schema({name:String}); var ParentSchema = new Schema({ children1:ChildSchema1, // 嵌套 Document children2:[ChildSchema2] // 嵌套 Documents }); 名词解释 exec(cb) 意义 ?cb 是 callback 的 意思 ,exec(cb) 即 执行 完 后 将 调用 callback 函数 , 你 可以 传 一个 函数 进去 , 例如 :db.collection.find(\"xxx\").exec(function(err,doc){ console.log(doc);}); ref 表示 表 collection 关联 ref 表示 关联 Post( 注意 : 被 关联 的 model 的 type 必须 是 ObjectId, Number, String, 和 Buffer 才 有效 )。var mongoose = require('mongoose');var Schema = mongoose.Schema;var UserSchema = new Schema({ name : { type: String, unique: true }, posts : [{ type: Schema.Types.ObjectId, ref: 'Post' }]});var User = mongoose.model('User', UserSchema);var PostSchema = new Schema({ poster : { type: Schema.Types.ObjectId, ref: 'User' }, comments : [{ type: Schema.Types.ObjectId, ref: 'Comment' }], title : String, content : String});var Post = mongoose.model('Post', PostSchema);var CommentSchema = new Schema({ post : { type: Schema.Types.ObjectId, ref: \"Post\" }, commenter : { type: Schema.Types.ObjectId, ref: 'User' }, content : String});var Comment = mongoose.model('Comment', CommentSchema); 在 上述 的 例子 中 , 创建 了 三个 Models:User,Post,Comment。User 的 属性 posts, 对应 是 一个 ObjectId 的 数组 。ref 表示 关联 Post( 注意 : 被 关联 的 model 的 type 必须 是 ObjectId, Number, String, 和 Buffer 才 有效 )。Post 的 属性 poster 和 comments 分别 关联 User 和 Comment。Comment 的 属性 post 和 commenter 分别 关联 Post 和 User。 三个 Models 的 关系 : 一个 user--has many-->post。 一个 post--has one-->user,has many-->comment。 一个 comment--has one-->post 和 user。 可视化 工具 - Robo 3T(Robomongo)mongoDB 操作 mongodb 数据库 操作 -- 备份 还原 导出 导入 1.mongodump 备份 数据库 >mongodump -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -o 文件 存在 路径 如果 没有 用户 谁 , 可以 去掉 -u 和 -p。 如果 导出 本 机 的 数据库 , 可以 去掉 -h。 如果 是 默认 端口 , 可以 去掉 --port。 如果 想 导出 所有 数据库 , 可以 去掉 -d。mongodump -h 127.0.0.1 -o E:\\mongoData - 导出 所有 数据库 mongodump -h 127.0.0.1 -d nodetao -o E:\\mongoData - 导出 指定 数据库 -d2.mongorestore 还原 数据库 >mongorestore -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 --drop 文件 存在 路径 --drop 的 意思 是 , 先 删除 所有 的 记录 , 然后 恢复 。3.mongoexport 导出 表 , 或者 表 中 部分 字 段 格式 :>mongoexport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表 名 -f 字 段 -q 条件 导出 --csv -o 文件名 上面 的 参数 好 理解 , 重点 说 一下 :-f 导出 指 字 段 , 以 字号 分割 ,-f name,email,age 导出 name,email,age 这 三个 字 段 -q 可以 根 查询 条件 导出 ,-q '{ \"uid\" : \"100\" }' 导出 uid 为 100 的 数据 --csv 表示 导出 的 文件格式 为 csv 的 , 这个 比较 有用 , 因为 大部分 的 关系 型 数据库 都 是 支持 csv, 在 这里 有 共同点 4.mongoimport 导入 表 , 或者 表 中 部分 字 段 1.1, 还原 整 表 导出 的 非 csv 文件 mongoimport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表 名 --upsert --drop 文件名 重点 说 一下 --upsert, 其他 参数 上面 的 命令 已有 提到 ,--upsert 插入 或者 更新 现有 数据 1.2, 还原 部分 字 段 的 导出 文件 mongoimport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表 名 --upsertFields 字 段 --drop 文件名 --upsertFields 根 --upsert 一样 1.3, 还原 导出 的 csv 文件 mongoimport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表 名 --type 类型 --headerline --upsert --drop 文件名 ","title":"MongoDb + mongoose 个人 整理 ","oriTitle":"MongoDb + mongoose 个人整理"},{"uri":"/posts/summary-ajax-learn","tags":["ajax"],"content":"[toc] 简单 应用 1.$.ajax 默认 为 异步 请求 ,async:true,2..post 方法 是 异步 的 https://api.jquery.com/jQuery.post/http://stackoverflow.com/questions/5821380/how-to-make-a-jquery-post-request-synchronous$.post(url,{jsonparam:json},function(data){ console.log(data) }).error(function(xhr,errorText,errorType){ alert(errorText) })$.post 只是 简化版 的 ajax 是 异步 的 HTML 标签 的 enctype 属性语法 `` 属性 值 | 值 | 描述 || ---------------------------------------------- |:--------------------------------------------------------------------------------------------:|| application/x-www-form-urlencoded | 在 发送 前 编码 所有 字符 ( 默认 ) || multipart/form-data | 不 对 字符 编码 。 在 使用 包含 文件 上传 控件 的 表单 时 , 必须 使用 该 值 。|| text/plain | 空格 转换 为 \"+\" 加号 , 但 不 对 特殊字符 编码 。 |## 四种 常见 的 POST 提交 数据 方式 HTTP/1.1 协议 规定 的 HTTP 请求 方法 有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这 几种 。 其中 POST 一般 用来 向 服务端 提交 数据 , 本文 主要 讨论 POST 提交 数据 的 几种 方式 。 我们 知道 ,HTTP 协议 是 以 ASCII 码 传输 , 建立 在 TCP/IP 协议 之上 的 应用层 规范 。 规范 把 HTTP 请求 分为 三个 部分 : 状态 行 、 请求 头 、 消息 主体 。 类似 于 下面 这样 : 协议 规定 POST 提交 的 数据 必须 放在 消息 主体 (entity-body) 中 , 但 协议 并 没有 规定 数据 必须 使用 什么 编码方式 。 实际上 , 开发者 完全 可以 自己 决定 消息 主体 的 格式 , 只要 最后 发送 的 HTTP 请求 满足 上面 的 格式 就 可以 。 但是 , 数据 发送 出去 , 还要 服务端 解析 成功 才 有 意义 。 一般 服务端 语言 如 php、python 等 , 以及 它们 的 framework, 都 内置 了 自动 解析 常见 数据格式 的 功能 。 服务端 通常 是 根据 请求 头 (headers) 中 的 Content-Type 字 段 来 获知 请求 中 的 消息 主体 是 用 何种 方式 编码 , 再 对 主体 进行 解析 。 所以 说 到 POST 提交 数据 方案 , 包含 了 Content-Type 和 消息 主体 编码方式 两 部分 。 下面 就 正式 开始 介绍 它们 。application/x-www-form-urlencoded 这 应该 是 最 常见 的 POST 提交 数据 的 方式 了 。 浏览器 的 原生 form 表单 , 如果 不 设置 enctype 属性 , 那么 最终 就 会 以 application/x-www-form-urlencoded 方式 提交 数据 。 请求 类似 于 下面 这样 ( 无关 的 请求 头 在 本文 中 都 省略 掉 了 ):(POST http://www.example.com HTTP/1.1)Content-Type: application/x-www-form-urlencoded;charset=utf-8title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3 首先 ,Content-Type 被 指定 为 application/x-www-form-urlencoded; 其次 , 提交 的 数据 按照 key1=val1&key2=val2 的 方式 进行 编码 ,key 和 val 都 进行 了 URL 转码 。 大部分 服务端 语言 都 对 这种 方式 有 很 好 的 支持 。 例如 PHP 中 ,POST[′title′] 可以 获取 到 title 的 值 ,POST[′title′] 可以 获取 到 title 的 值 ,_POST['sub'] 可以 得到 sub 数组 。 很多 时候 , 我们 用 Ajax 提交 数据 时 , 也 是 使用 这种 方式 。 例如 JQuery 和 QWrap 的 Ajax,Content-Type 默认值 都 是 「application/x-www-form-urlencoded;charset=utf-8」。multipart/form-data 这 又 是 一个 常见 的 POST 数据 提交 的 方式 。 我们 使用 表单 上传 文件 时 , 必须 让 form 的 enctyped 等于 这个 值 。 直接 来看 一个 请求 示例 :POST http://www.example.com HTTP/1.1Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA------WebKitFormBoundaryrGKCBY7qhFd3TrwAContent-Disposition: form-data; name=\"text\"title------WebKitFormBoundaryrGKCBY7qhFd3TrwAContent-Disposition: form-data; name=\"file\"; filename=\"chrome.png\"Content-Type: image/pngPNG ... content of chrome.png ...------WebKitFormBoundaryrGKCBY7qhFd3TrwA-- 这个 例子 稍微 复杂 点 。 首先 生成 了 一个 boundary 用于 分割 不同 的 字 段 , 为了 避免 与 正文 内容 重复 ,boundary 很 长 很 复杂 。 然后 Content-Type 里 指明 了 数据 是 以 mutipart/form-data 来 编码 , 本次 请求 的 boundary 是 什么 内容 。 消息 主体 里 按照 字 段 个数 又 分为 多个 结构 类似 的 部分 , 每 部分 都 是 以 --boundary 开始 , 紧接着 内容 描述 信息 , 然后 是 回车 , 最后 是 字 段 具体内容 ( 文本 或 二进制 )。 如果 传输 的 是 文件 , 还要 包含 文件名 和 文件类型 信息 。 消息 主体 最后 以 --boundary-- 标示 结束 。 关于 mutipart/form-data 的 详细 定义 , 请 前往 rfc1867 查看 。 这种 方式 一般 用来 上传 文件 , 各 大 服务端 语言 对 它 也 有着 良好 的 支持 。 上面 提到 的 这 两种 POST 数据 的 方式 , 都 是 浏览器 原生 支持 的 , 而且 现阶段 原生 form 表单 也 只 支持 这 两种 方式 。 但是 随着 越来越 多 的 Web 站点 , 尤其 是 WebApp, 全部 使用 Ajax 进行 数据 交互 之后 , 我们 完全 可以 定义新 的 数据 提交 方式 , 给 开发 带来 更 多 便利 。application/jsonapplication/json 这个 Content-Type 作为 响应 头 大家 肯定 不 陌生 。 实际上 , 现在 越来越 多 的 人 把 它 作为 请求 头 , 用来 告诉 服务端 消息 主体 是 序列化 后 的 JSON 字符串 。 由于 JSON 规范 的 流行 , 除了 低版本 IE 之外 的 各 大 浏览器 都 原生 支持 JSON.stringify, 服务端 语言 也 都 有 处理 JSON 的 函数 , 使用 JSON 不会 遇上 什么 麻烦 。JSON 格式 支持 比 键值 对 复杂 得 多 的 结构化 数据 , 这 一点 也 很 有用 。 记得 我 几年 前 做 一个 项目 时 , 需要 提交 的 数据 层次 非常 深 , 我 就是 把 数据 JSON 序列化 之后 来 提交 的 。 不过 当时 我 是 把 JSON 字符串 作为 val, 仍然 放在 键值 对 里 , 以 x-www-form-urlencoded 方式 提交 。>Google 的 AngularJS 中 的 Ajax 功能 , 默认 就是 提交 JSON 字符串 。 例如 下面 这 段 代码 :var data = {'title':'test', 'sub' : [1,2,3]};$http.post(url, data).success(function(result) {...}); 最终 发送 的 请求 是 :POST http://www.example.com HTTP/1.1Content-Type: application/json;charset=utf-8{\"title\":\"test\",\"sub\":[1,2,3]} 这种 方案 , 可以 方便 的 提交 复杂 的 结构化 数据 , 特别 适合 RESTful 的 接口 。 各 大 抓 包 工具 如 Chrome 自带 的 开发者 工具 、Firebug、Fiddler, 都 会 以 树形 结构 展示 JSON 数据 , 非常 友好 。 但 也 有些 服务端 语言 还 没有 支持 这种 方式 , 例如 php 就 无法 通过 $POST 对象 从 上面 的 请求 中 获得 内容 。 这时候 , 需要 自己 动手 处理 下 : 在 请求 头 中 Content-Type 为 application/json 时 , 从 php://input 里 获得 原始 输入 流 , 再 jsondecode 成 对象 。 一些 php 框架 已经 开始 这么 做 了 。 当然 AngularJS 也 可以 配置 为 使用 x-www-form-urlencoded 方式 提交 数据 。 如 有 需要 , 可以 参考 这 篇文章 。text/xml 我 的 博客 之前 提到 过 XML-RPC(XML Remote Procedure Call)。 它 是 一种 使用 HTTP 作为 传输 协议 ,XML 作为 编码方式 的 远程 调用 规范 。 典型 的 XML-RPC 请求 是 这样 的 :POST http://www.example.com HTTP/1.1Content-Type: text/xmlexamples.getStateName41XML-RPC 协议 简单 、 功 能够 用 , 各种 语言 的 实现 都 有 。 它 的 使用 也 很 广泛 , 如 WordPress 的 XML-RPC Api, 搜索引擎 的 ping 服务 等等 。JavaScript 中 , 也 有 现成 的 库 支持 以 这种 方式 进行 数据 交互 , 能 很 好 的 支持 已有 的 XML-RPC 服务 。 不过 , 我 个人 觉得 XML 结构 还是 过于 臃肿 , 一般 场景 用 JSON 会 更 灵活 方便 。x-www-form-urlencoded 与 multipart/form-data 区别 , 如何 选择 ?www-form-urlencoded 是 POST 数据 默认 编码 格式 ,POST 过去 的 key-value 会 被 编码 成 QueryString, 格式 如下 :name=test&gender=male&[email protected] 服务器端 对 接受 数据 的 处理 也 很 简单 。json 一般 更 多 用来 返回 数据 而 不是 在 提交 数据 的 时候 使用 , 通常 Restful 服务 都 会 支持 json/xml 格式 的 返回 数据 。json 对象 及其 编解码 在 各个 平台 ( 无论 服务器 、 电脑 还是 手机 ) 都 有 很 好 的 支持 。 那么 怎么 选择 这 两种 方式 呢 ? 这 不是 一个 非 错 即 对 的 选择 , 但 可以 参考 如下 的 实践 建议 : 如果 数据 是 简单 、 平面 的 key-value 数值 对 , 那么 使用 www-form-urlencoded 简单 实用 , 不 需要 额外 的 编解码 ; 如果 数据 是 复杂 的 嵌套 关系 , 有 多层 数据 , 那么 使用 json 会 简化 数据 的 处理 , 从而 更 高效 。>http 请求 场景 : 前端 :SDK 通过 http 发送 请求 / 页面 Ajax 提交 。 后台 :Springboot 服务 ,Rest 风格 , 需 在 controller 层 之前 拦截 请求 。Springboot 支持 Rest 风格 给 编码 带来 了 很 好 的 便捷性 ,@RequestBody 让 我们 可以 直接 以 application/json 请求 并 在 到达 controller 层 获得 已 反 序列化 的 对象 , 当 有 拦截 的 需求 , 这种 方式 却 不再 奏效 。application/x-www-form-urlencoded 通过 表单 提交 , 在 sevlet 实现 中 ,mutipart/form-data 和 application/x-www-form-urlencoded 会 被 特殊 处理 , 请求 参数 将 被 放置 于 request.paramter, 这 是 一个 map。 我们 可以 从 map 中 获取 参数 进行 验证 , 或者 其他 拦截 需求 ,map 的 获取 类似 hibernate 的 延迟 加载 , 当 调用 request.getparamter() 方法 ,servlet 才 会 从 请求 流 中 读取 请求 参数 加 载入 map。InputStream 也 会 存有 这份 数据 , 但 如果 这份 数据 被 读取 , 那么 到 了 controller 层 将 无法 读出 数据 , 同样 , 拦截 之后 到达 controller 层 时 请求 数据 已经 被 加 载入 了 controller 层 方法 实参 , 实参 对象 需要 有 set 方法 , 框架 会 以 反射 的 方式 调用 属性 的 set 方法 注入 数据 , 数据 只 会 被 注入 到 已有 的 属性 。 当 以 application/json 的 content-type 传送数据 , 被 传送 的 对象 只 需 被 json 序列化 。 当 以 application/x-www-form-urlencoded 的 方式 传送数据 。 请求 的 内容 需要 以 ..=..&..=.. 的 格式 提交 , 在 请求 体内 内容 将 会 以 ”&” 和 “ = ” 进行 拆分 。app.controller('mailController', function($scope, $http) { $scope.guest = {}; $scope.authError = null; $scope.send = function() { var req = { method: 'POST', url: '/mail/send', headers: { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' }, data: \"from=\" + $scope.guest.from + '&' + \"subject=\" + $scope.guest.subject + '&' + \"content=\" + $scope.guest.content }; 将 提交 数据格式 改 一下 :data:$scope.guest.serialize() request.paramter 中将 以 key:{\"from\":\"[email protected]\",\"subject\":\" 主题 \",\"content\":\" 正文 \"}value:\"\" 的 形式 出现 。 但 你 需要 使用 content-type=application/json 且 后台 使用 @RequestBody, 你 无法 再 从 paramter 中 获取 请求 数据 。 选择 application/x-www-form-urlencoded 还是 application/json, 得 看 你 是否 有 从 request.paramter 获取 请求 数据 的 需求 。 个人 常 使用 情况 : 第一 :$.ajax({ type:\"POST\", url:\"${basePath}/wechat/food/wxFoodEval_addFoodEval\", async:true, data: $(\"#foodEvalForm\").serialize(), dataType:\"json\", success: function(data){ if(data.state) { layer.open({ content: \" 评价 成功 \", btn: [' 确认 '], shadeClose: false, time: 3, yes: function(index){ window.location.href = \"${basePath}/wx/food/foodEvalList.jsp?foodId=\"; }, end :function(index) { window.location.href = \"${basePath}/wx/food/foodEvalList.jsp?foodId=\"; } }); } else { alertTips(\" 系统 错误 , 请 联系 客服 或 重新 尝试 \"); } layer.close(layerLoad); }}); 第二 :$.post(\"${basePath}/wxBooking/WxBookingTime_getBookingDateAndTime\",null,function(data) { if(data.state) { var dayArrays = data.dayArrays; var timeArr = data.timeList; var daySelect = \" 请 选择 日期 \"; var bookingTimeSelect = \" 请 选择 时间 \"; if(timeArr != null && timeArr.length > 0) { for(var i in dayArrays) { daySelect += \"\"+dayArrays[i]+\"\"; } for(var j in timeArr) { bookingTimeSelect += \"\"+timeArr[j]+\"\"; } } $(\"#chooseDate\").html(daySelect); $(\"#chooseTime\").html(bookingTimeSelect); } else { alertTips(\" 系统 错误 , 请 刷新 重试 \"); }});$.post(\"${bathPath}/wxBooking/WxAgeInterval_getPublishList\",null,function(data){ if(data.state){ var ageIntervalList=data.ageIntervalList; if(ageIntervalList !=null&&ageIntervalList.length>0){ var html=\"\"; for(i in ageIntervalList){ var ageInterval=ageIntervalList[i]; var ageIntervalStr=ageInterval.minAge+\"\"; if(ageInterval.maxAge !=0){ ageIntervalStr+=\"~\"+ageInterval.maxAge+\" 岁 \" }else{ ageIntervalStr+=\" 岁 以上 \" } html+=\"\"+ageIntervalStr+\"\"; } $(\"#ageIntervalUl\").append(html); } }})2.Form 表单 中 的 post 与 get 与 ajax 中 的 post get 作用 相同 么 ? 相同 的 , ajax, 中 ,,,data 传 参 , post 地址栏 不 可见 , 效率 稍低 。get 地址栏 可见 , 传输速度 快 , 但是 不 安全 。 表单 提交 同 上 form ajax 提交 , 推荐 使用 jquery.form.js $(\"#myForm\").ajaxSubmit(options);$(\"#myForm\").ajaxForm(options);// 示例 图片 上传 //script$(formOjb).ajaxSubmit({ url:\"attachsUpload\", type:\"post\", dataType:'json', timeout: 60000, success:function(data){ if(\"0000\" == data.code && data.data) { $this.parents(\"td\").find(\"img\").attr(\"src\", getImgPath(data)); $this.parents(\"td\").find(\".fancybox-buttons\").attr(\"href\", getImgPath(data)); var url = 'quickorder/updatePicByImgCode.html'; var jsonparam = {}; jsonparam.imgUrl = data.data.imgPath; jsonparam.id = $this.attr('data-id'); var jsonparam = $.toJSON(jsonparam); $.ajax({ type:\"post\", url:url, data:{jsonparam:jsonparam}, success:function(data) { if (\"0000\" == data.code) { alertMsg.correct(\" 操作 成功 !\"); } else { alertMsg.error(\" 操作 失败 !\"+data.desc); } } }); }else{ alertMsg.error(data.desc); } }, error:function(xhr, ajaxOptions, thrownError){ alertMsg.error(\" 网络 异常 , 请 稍后 重试 !\"); }});Form 表单 插件 jquery.form.js ajaxForm 和 ajaxSubmitjQuery Form 插件 是 一个 优秀 的 Ajax 表单 插件 , 可以 非常容易 地 、 无 侵入 地 升级 HTML 表单 以 支持 Ajax。jQuery Form 有 两个 核心 方法 -- ajaxForm() 和 ajaxSubmit(), 它们 集合 了 从 控制 表单 元素 到 决定 如何 管理 提交 进程 的 功能 。 另外 , 插件 还 包括 其他 的 一些 方法 : formToArray()、formSerialize()、fieldSerialize()、fieldValue()、clearForm()、clearFields() 和 resetForm() 等 。 下载 地址 : http://malsup.com/jquery/form/#download 核心 方法 -- ajaxForm() 和 ajaxSubmit()ajaxsubmit 更 偏向 于 处理 form 表单 , 而 post 的 方式 更 全面 一些 。 提交 表单 自然 优先选择 ajaxsubmit, 如果 只是 提交 下 post 请求 那 还是 post 的 方式 更 实在 ajaxsubmit 支持 文件 上传 ajax, 采用 自己 写 的 ajax 代码 。$('#myForm').ajaxForm(function() { $('#output1').html(\" 提交 成功 ! 欢迎 下次 再 来 !\").show();});$('#myForm2').submit(function() { $(this).ajaxSubmit(function() { $('#output2').html(\" 提交 成功 ! 欢迎 下次 再 来 !\").show(); }); return false; // 阻止 表单 默认 提交 }); 通过 Form 插件 的 两个 核心 方法 , 都 可以 在 不 修改 表单 的 HTML 代码 结构 的 情况 下 , 轻易 地 将 表单 的 提交 方式 升级 为 Ajax 提交 方式 ajaxForm() 和 ajaxSubmit() 都 能 接受 0 个 或 1 个 参数 , 当 为 单个 参数 时 , 该 参数 既 可以 是 一个 回调 函数 , 也 可以 是 一个 options 对象 , 上面 的 例子 就是 回调 函数 , 下面 介绍 options 对象 , 使得 它们 对 表单 拥有 更 多 的 控制权 var options = { target: '#output', // 把 服务器返回 的 内容 放入 id 为 output 的 元素 中 beforeSubmit: showRequest, // 提交 前 的 回调 函数 success: showResponse, // 提交 后 的 回调 函数 //url: url, // 默认 是 form 的 action, 如果 申明 , 则 会 覆盖 //type: type, // 默认 是 form 的 method(get or post), 如果 申明 , 则 会 覆盖 //dataType: null, //html( 默认 ), xml, script, json... 接受 服务端 返回 的 类型 //clearForm: true, // 成功 提交 后 , 清除 所有 表单 元素 的 值 //resetForm: true, // 成功 提交 后 , 重置 所有 表单 元素 的 值 timeout: 3000 // 限制 请求 的 时间 , 当 请求 大于 3 秒 后 , 跳出 请求 }function showRequest(formData, jqForm, options){ //formData: 数组 对象 , 提交 表单 时 ,Form 插件 会 以 Ajax 方式 自动 提交 这些 数据 , 格式 如 :[{name:user,value:val },{name:pwd,value:pwd}] //jqForm: jQuery 对象 , 封装 了 表单 的 元素 //options: options 对象 var queryString = $.param(formData); //name=1&address=2 var formElement = jqForm[0]; // 将 jqForm 转换 为 DOM 对象 var address = formElement.address.value; // 访问 jqForm 的 DOM 元素 return true; // 只要 不 返回 false, 表单 都 会 提交 , 在 这里 可以 对 表单 元素 进行 验证 };function showResponse(responseText, statusText){ //dataType=xml var name = $('name', responseXML).text(); var address = $('address', responseXML).text(); $(\"#xmlout\").html(name + \" \" + address); //dataType=json $(\"#jsonout\").html(data.name + \" \" + data.address);};$(\"#myForm\").ajaxForm(options);$(\"#myForm2\").submit(funtion(){ $(this).ajaxSubmit(options); return false; // 阻止 表单 默认 提交 }); 表单 提交 之前 进行 验证 : beforeSubmit 会 在 表单 提交 前 被 调用 , 如果 beforeSubmit 返回 false, 则 会 阻止 表单 提交 beforeSubmit: validatefunction validate(formData, jqForm, options) { // 在 这里 对 表单 进行 验证 , 如果 不 符合 规则 , 将 返回 false 来 阻止 表单 提交 , 直到 符合 规则 为止 // 方式 一 : 利用 formData 参数 for (var i=0; i 小 图 中 图 大 图 ","title":"ajax 个人 整理 ","oriTitle":"ajax 个人整理"},{"uri":"/posts/summary-git-learn","tags":["Summary","git"],"content":"[toc]Git ssh 生成 ssh-keygen -t rsa -C \"[email protected]\" -f \"jlpayPro\" ssh-keygen - 生成 、 管理 和 转换 认证 密钥 ssh-keygen [-q] [-b bits] -t type [-N newpassphrase] [-C comment] [-foutputkeyfile] ssh-keygen -p [-P oldpassphrase] [-N newpassphrase] [-f keyfile] ssh-keygen -i [-f input_keyfile] ssh-keygen -e [-f input_keyfile] ssh-keygen -y [-f input_keyfile] ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile] ssh-keygen -l [-f input_keyfile] ssh-keygen -B [-f input_keyfile] ssh-keygen -D reader ssh-keygen -F hostname [-f knownhostsfile] ssh-keygen -f filename ssh-keygen -H [-f knownhostsfile] ssh-keygen -R hostname [-f knownhostsfile] ssh-keygen -U reader [-f input_keyfile] ssh-keygen -r hostname [-f input_keyfile] [-g] ssh-keygen -G outputfile [-v] [-b bits] [-M memory] [-S startpoint] ssh-keygen -T outputfile -f inputfile [-v] [-a num_trials] [-W generator] ssh-keygen 用于 为 生成 、 管理 和 转换 认证 密钥 , 包括 RSA 和 DSA 两种 密钥 。Git 常用命令 速查表 git add -A ,git add .,git add -u 区别 1. git add -A 保存 所有 的 修改 2. git add . 保存 新 的 添加 和 修改 , 但是 不 包括 删除 3. git add -u 保存 修改 和 删除 , 但是 不 包括 新建 文件 。 本地 仓库 推送 git init // 初始化 仓库 git add .( 文件 name) // 添加 文件 到 本地 仓库 git commit -m \"first commit\" // 添加 文件 描述 信息 git remote add origin + 远程 仓库 地址 // 链接 远程 仓库 , 创建 主 分支 git pull origin master // 把 本地 仓库 的 变化 连接 到 远程 仓库 主 分支 git push -u origin master // 把 本地 仓库 的 文件 推送 到 远程 仓库 git push -u origin master -f // 强制 推送 git 分支 >git branch 新建 分支 >git checkout 切换 本地 分支 >git push origin dev 提交 该 分支 到 远程 仓库 >git pull origin xf:xf 把 远程 分支 的 代码 pull 到 本地 分支 :git pull :>git push origin xf:xf 将 本地 的 xf 分支 推送 到 origin 主机 的 xf 分支 。>git push origin test 将 本地 的 test 分支 推送 到 origin 主机 的 test 分支 。 如果 后者 不 存在 , 则 会 被 新建 。git checkout -b iss53 // 创建 新 分支 并 选择 该 分支 它 是 下面 两条 命令 的 简写 :$ git branch iss53$ git checkout iss53git branch -r 命令 查看 远端 库 的 分支 情况 git branch -a 查看 所有 分支 , 包含 本地 远程 $ git push origin dbglichenstar:dbglichenstar // 把 新建 的 本地 分支 push 到 远程 服务器 , 远程 分支 与 本地 分支 同名 ( 当然 可以 随意 起名 ): 解决 git 本地 仓库 push 远程 仓库 的 时候 , 报 了 异常 :fatal the current branch master has no upstream branch1. 翻译 后 大致 意思 是 , 远程 仓库 创建 时候 要 建立 一个 README 文件 , 然后 再 进行 push 操作 。 因为 这个 文件 是 远程 仓库 主 分支 所 必须 的 , 见 如下 截图 。git push -u origin mastergit commit 中文 报错 Warning: Your console font probably doesn't support Unicode 应该 是 字符 不 对 , 所以 在 粘贴 之前 先 修改 一下 字符 , 用 这个 命令 :$ git config --global core.autocrlf trueGit 的 撤消 操作 - 重置 , 签出 和 撤消 , 和 储藏 修复 未 提交 文件 中 的 错误 ( 重置 )git checkout . 本地 所有 修改 , 没有 提交 的 返回 原来 的 状态 ;git reset --hard HEAD 让 工作 目录 回到 上次 提交 时 的 状态 (last committed state):git checkout -- hello.rb 只是 要 恢复 一个 文件 , 如 \"hello.rb\", 你 就要 使用 git checkoutgit reset --hard FETCH_HEADlocal 文件 冲突 了 1.pull 会 使用 git merge 导致 冲突 , 需要 将 冲突 的 文件 resolve 掉 git add -u, git commit 之后 才能 成功 pull.2. 如果 想 放弃 本地 的 文件 修改 , 可以 使用 git reset --hard FETCHHEAD,FETCHHEAD 表示 上 一次 成功 git pull 之后 形成 的 commit 点 。 然后 git pull. 注意 :git merge 会 形成 MERGE-HEAD(FETCH-HEAD) 。git push 会 形成 HEAD 这样 的 引用 。HEAD 代表 本地 最近 成功 push 后 形成 的 引用 。 在 git push 的 时候 , 有时候 我们 会 想 办法 撤销 git commit 的 内容 1、 找到 之前 提交 的 git commit 的 idgit log 找到 想要 撤销 的 id2、git reset –hard id 完成 撤销 , 同时 将 代码 恢复 到 前 一 commit_id 对应 的 版本 3、git reset id 完成 Commit 命令 的 撤销 , 但是 不 对 代码 修改 进行 撤销 , 可以 直接 通过 git commit 重新 提交 对 本地 代码 的 修改 修复 已 提交 文件 中 的 错误 git revert HEAD 撤消 了 上次 提交 (HEAD) 的 新 提交 , 你 就 有 机会 来 修改 新 提交 (new commit) 里 的 提交 注释 信息 .git revert HEAD^ 你 也 可 撤消 更 早期 的 修改 , 下面 这 条 命令 就是 撤消 “ 上 上次 ”(next-to-last) 的 提交 :git 冲突 You are not currently on a branch. 首先 git checkout -b temp 其次 git checkout master 即可 恢复 到 master repository 的 状态 , 然后 就 可以 pull 了 储藏 (Stashing)git stash 参考 commit message 格式 格式 语法 每次 提交 ,Commit message 都 包括 三个 部分 :Header,Body 和 Footer。Header 为 必须 ():// 空 一行 // 空 一行 // 例 :feat(gulp):gulp 增加 ruby-scss 控制 Header 部分 只有 一行 , 包括 三个 字 段 :type( 必需 )、scope( 可 选 ) 和 subject( 必需 )。Body 部分 是 对 本次 commit 的 详细描述 , 可以 分成 多行 。More detailed explanatory text, if necessary. Wrap it toabout 72 characters or so.Further paragraphs come after blank lines.Bullet points are okay, tooUse a hanging indent1.commitizen 依赖 及 生成 工具 $ npm install -g commitizen //commit message 撰写 工具 $ commitizen init cz-conventional-changelog --save --save-exact // 项目 目录 里 , 运行 下面 的 命令 , 使 其 支持 Angular 的 Commit message 格式 。 以后 , 凡是 用到 git commit 命令 , 一律 改为 使用 git cz。 这时 , 就 会 出现 选项 , 用来 生成 符合 格式 的 Commit message。| 生成 changelognpm install -g conventional-changelognpm install -g conventional-changelog-cli$ conventional-changelog -p angular -i CHANGELOG.md -w // 上面 命令 不会 覆盖 以前 的 Change log, 只 会 在 CHANGELOG.md 的 头部 加上 自从 上次 发布 以来 的 变动 。conventional-changelog -p angular -i CHANGELOG.md -w -r 0 // 想 生成 所有 发布 的 Change log, 要 改为 运行 下面 的 命令 。2.changelog.md commit 内容 回退 , 修改 git commit --amend 或者 (git cz --amend) 如果 已经 通过 git push 提交 了 , 看 你们 公司 用 的 什么 git 服务器 了 , 一般 用户 想 修改 的话 需要 相关 的 权限 , 找 管理员 了 ; 如果 已经 有 其他 开发人员 基于 你 的 提交 进行 了 修改 并 提交 的话 , 那 就 更 麻烦 了 , 后面 的 所有 提交 都 要 重新 做 一遍 ; 如果 还 没有 push 到 服务器 , 只是 本地 进行 了 commit, 并且 没有 进行 新 的 commit, 只 需要 git commit --amend; 如果 进行 了 新 的 commit, 只 需要 git reset --soft xxx (xxx 有 问题 那次 提交 的 commit id), 然后 在 进行 git commit 就 行 , 不过 所有 后面 的 提交 都 成为 了 一次 提交 ; 如果 想 保持 每次 提交 独立 的话 , 使用 git checkout -b tmp ^xxxgit cherry-pick xxxgit commit --amendgit cherry-pickvim 模式 写 commit message1. 摁 键盘 i, 最 下面 有所 变化 2. 此时 光标 在 最 上面 , 输入 要 替 提交 的 说明 'comment', 嗯 Esc, 然后 输入 :, 光标 跑 到 了 最 下面 3. 输入 wq 之后 , 摁 回车 即可 , 就要 回到 了 原始 的 命令行 界面 vim 模式 下 报错 E37: No write since last change (add ! to override) 故障 现象 : 使用 vim 修改 文件 报错 , 系统 提示 如下 :E37: No write since last change (add ! to override) 故障 原因 : 文件 为 只读 文件 , 无法 修改 。 解决办法 : 使用 命令 :w! 强制 存盘 即可 , 在 vim 模式 下 , 键入 以下 命令 ::w! 存盘 后 在 使用 vim 命令 检查 是否 保存 , 如 未 保存 , 编辑 后 重复 以上 操作 。 或者 报出 linux 中 vi 保存 文件 时 的 “Can't open file for writing”E212: Can't open file for writingPress ENTER or type command to continue 出现 这个 错误 的 原因 可能 有 两个 : 一 是 当前 用户 的 权限 不足 , 二 是 此 文件 可能 正 被 其他 程序 或 用户 使用 。 这里 的 错误 原因 是 前者 , 解决方案 是 在 使用 vi 命令 打开 文件 时 , 前面 加上 sudo 来 临时 提供 管理员 权限 , 即 使用 命令 “sudo vi grub.cfg” 打开 编辑 文件 。 由此看来 ,sudo 命令 是 很 有用 的 , 当 我们 执行 某种 操作系统 提示 诸如 “operation not permitted” 等 权限 不足 信息 时 , 我们 很多 时候 都 可以 在 命令 前面 加上 sudo 来 解决 权限 不足 问题 git 错误 整理 with the from the remote, but no such ref was fetched.?> 解决 :git branch --set-upstream master origin/mastergit checkout 行 结束符 CRLF LF 问题 主要 的 原因 在 与 文件 的 结尾 标识符 。CRLF->Windows styleLF->Unix StyleCR->Mac StyleCRLF 表示 句 尾 使用 回车 换行 两个 字符 ( 即 我们 常 在 Windows 编程 时 使用 ”\\r\\n” 换行 ) LF 表示 表示 句 尾 , 只 使用 换行 . CR 表示 只 使用 回车 .Git 可以 在 你 提交 时 , 自动 地 把 行 结束符 CRLF 转换成 LF, 而 在 签出 代码 时 把 LF 转换成 CRLF 。 用 core.autocrlf 来 打开 此项 功能 , 如果 是 在 Windows 系统 上 , 把 它 设置 成 true, 这样 当 签出 代码 时 ,LF 会 被 转换成 CRLF: git config –global core.autocrlf trueLinux 或 Mac 系统 使用 LF 作为 行 结束符 , 因此 你 不想 Git 在 签出 文件 时 进行 自动 的 转换 ; 当 一个 以 CRLF 为 行 结束符 的 文件 不 小心 被 引入 时 , 你 肯定 想 进行 修正 , 把 core.autocrlf 设置 成 input 来 告诉 Git 在 提交 时 把 CRLF 转换成 LF, 签出 时 不 转换 : git config –global core.autocrlf input 参考 上面 的 配置 方法 , 你 就 可以 在 Windows 系统 上 , 签出 文件 时 保留 CRLF, 而 在 Mac 和 Linux 系统 上 , 包括 仓库 中 , 保留 LF 。 如果 你 是 Windows 程序员 , 且 正在 开发 仅 运行 在 Windows 上 的 项目 , 可以 设置 false 取消 此 功能 , 把 回车符 记录 在 库 中 : git config –global core.autocrlf false 这次 我 这边 的 修改 是 , 使用 了 git config –global core.autocrlf input 该 命令 , 将 问题 解决 了 。 也 可以 在 windows 重新安装 git 工具 ,git 安装 过程 中 , 有 个 选项 , 可以 通过 这个 选项 来 选择 选 择 core.autocrlf 默认 配置 。","title":"GIT【 个人 整理 】","oriTitle":"GIT【个人整理】"},{"uri":"/posts/summary-hack-person-setting","tags":["hack","Summary"],"content":"css 浏览器 兼容 _ IE6 * IE6/7 !important IE7/Firefox *+ IE7 \\9 IE6/7/8 \\0 IE8 条件 hack IE7 以下 版本 IE7 IE8 IE8 以上 DTD 文档 声明 // 用于 XHTML 4.0 的 严格 型 // 用于 XHTML 4.0 的 过渡型 // 用于 XHTML 1.0 的 严格 型 // 用于 XHTML 1.0 的 过渡型 DTD 全称 Document Type Definition, 即 文档 类型定义 . 如果 漏 写 DTD 声明 ,Firefox 仍然 会 按照 标准 模式 来 解析 网页 , 但 在 IE 中 ( 包括 IE6,IE7,IE8) 就 会 出发 怪异 模式 . 事件 兼容 event.preventDefault IE 兼容 event.preventDefault ? event.preventDefault() : (event.returnValue = false);background-size IE8 兼容 方法 一 :filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/logo.gif',sizingMethod='scale');-ms-filter: \"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/logo.gif',sizingMethod='scale')\";① 不能 指定 任意 大小 background 百分比 , 可用 cover,② 用于 单张 图片 不能 使用 图片 精灵 等 拼图 ,③ 要 引用 绝对路径 图片 ,④ 兼容 ie7,8 方法 二 :.selector { background-size: cover; -ms-behavior: url(/backgroundsize.min.htc); }GitHub - louisremi/background-size-polyfill: Adds support for background-size \"cover\" and \"contain\" to IE8① 可 指定 百分比 ,②.htc 要 相对 文档 路径 ,③ 兼容 ie7,8","title":"【hack】 个人 整理 ","oriTitle":"【hack】个人整理"},{"uri":"/posts/summary-html5-learn","tags":["Summary","html"],"content":"[toc]HTML5 中 类 jQuery 选择器 querySelector 的 使用 简介 HTML5 向 Web API 新 引入 了 document.querySelector 以及 document.querySelectorAll 两个 方法 用来 更 方便 地 从 DOM 选取 元素 , 功能 类似 于 jQuery 的 选择器 。 这 使得 在 编写 原生 JavaScript 代码 时 方便 了 许多 。 用法 两个 方法 使用 差不多 的 语法 , 都 是 接收 一个 字符串 参数 , 这个 参数 需要 是 合法 的 CSS 选择 语法 。element = document.querySelector('selectors');elementList = document.querySelectorAll('selectors'); 其中 参数 selectors 可以 包含 多个 CSS 选择器 , 用 逗号 隔开 。element = document.querySelector('selector1,selector2,...');elementList = document.querySelectorAll('selector1,selector2,...'); 使用 这 两个 方法 无法 查找 带 伪 类 状态 的 元素 , 比如 querySelector(':hover') 不会 得到 预期 结果 。querySelector 和 querySelectorAll IE8+ 浏览器 支持 。querySelector 返回 的 是 单个 DOM 元素 ;querySelectorAll 返回 的 是 NodeList. 我们 一般 用 的 多 的 是 document.querySelectorAll, 实际上 , 也 支持 dom.querySelectorAll. 例如 :document.querySelector(\"#my-id\").querySelectorAll(\"img\") 选择 的 就是 里面 这个 妹子 。 例如 , 我 在 控制台 输出 该 选择 NodeList 的 长度 和 id, 如下 截图 ://testdocument.querySelectorAll(\"#my-id div div\").length === 1;document.querySelector(\"#my-id\").querySelectorAll(\"div div\").length === 3; 这里 的 querySelectorAll 里面 的 选择器 也 同样 是 这 也 全局 特性 。document.querySelector(\"#my-id\").querySelectorAll(\"div div\") 翻译成 白话文 就是 : 查询 #my-id 的 子 元素 , 同时 满足 整个 页面 下 div div 选择器 条件 的 DOM 元素 们 。 我们 页面 往 上 滚动 看看 原始 的 HTML 结构 , 会 发现 , 在 全局 视野 下 ,div.lonely, div.outer, div.inner 全部 都 满足 div div 这个 选择器 条件 , 于是 , 最终 返回 的 长度 为 3.:scope 与 区域 选择 限制 其实 , 要 想 querySelectorAll 后面 选择器 不 受 全局 影响 , 也 是 有 办法 的 , 就是 使用 目前 还 处于 实验 阶段 的 :scope 伪 类 , 其 作用 就是 让 CSS 是 在 某 一 范围 内 使用 。 此 伪 类 在 CSS 中 使用 是 大头 , 但是 也 可以 在 querySelectorAll 语句 中 使用 :document.querySelector(\"#my-id\").querySelectorAll(\":scope div div\");querySelector 该 方法 返回 满足条件 的 单个 元素 。 按照 深度 优先 和 先 序 遍历 的 原则 使用 参数 提供 的 CSS 选择器 在 DOM 进行 查找 , 返回 第一个 满足条件 的 元素 。element = document.querySelector('div#container');// 返回 id 为 container 的 首个 divelement = document.querySelector('.foo,.bar');// 返回 带有 foo 或者 bar 样式 类 的 首个 元素 querySelectorAll 该 方法 返回 所有 满足条件 的 元素 , 结果 是 个 nodeList 集合 。 查找 规则 与 前面 所述 一样 。elements = document.querySelectorAll('div.foo');// 返回 所有 带 foo 类 样式 的 div 但 需要 注意 的 是 返回 的 nodeList 集合 中 的 元素 是非 实时 (no-live) 的 , 想要 区别 什么 是 实时 非 实时 的 返回 结果 , 请 看 下 例 :// 首先 选取 页面 中 id 为 container 的 元素 container=document.getElementById('#container');console.log(container.childNodes.length)// 结果 为 2// 然后 通过 代码 为 其 添加 一个 子 元素 container.appendChild(document.createElement('div'));// 这个 元素 不但 添加 到 页面 了 , 这里 的 变量 container 也 自动更新 了 console.log(container.childNodes.length)// 结果 为 3 通过 上面 的 例子 就 很 好 地 理解 了 什么 是 会 实时 更新 的 元素 。document.getElementById 返回 的 便是 实时 结果 , 上 面对 其 添加 一个 子 元素 后 , 再次 获取 所有 子 元素 个数 , 已经 由 原来 的 2 个 更新 为 3 个 ( 这里 不 考虑 有些 浏览器 比如 Chrome 会 把 空白 也 解析 为 一个 子 节点 )。 关于 转义 我们 知道 反 斜杠 是 用来 转义 用 的 , 比如 在 字符串 里 我们 想 表示 空字符 就 使用 '\\b', 换行 '\\n'。 同样 , 在 提供 给 querySelector 和 querySelectorAll 的 参数 也 支持 转义 , 了解 这点 非常 重要 。 先 看 个 例子 , 比如 我们 有 个 div 它 的 样式 类 为 'foo:bar', 当然 我 知道 你 一般 不会 这样 写 。 当 我们 需要 选择 它 的 时候 , 就 需要 将 其中 的 冒号 进行 转义 , 否则 抛 错 。`` 浏览器 报怨 表示 不是 一个 合法 的 选择 语句 。 同时 , 有趣 的 事情 来 了 , 或许 你 以为 将 冒号 直接 转义 就 解决问题 了 。 同样 , 也 表示 非法 。 原因 就 在于 反 斜杠 在 字符串 中 本身 就 表示 转义 的 意思 , 它 于 冒号 结合 转 不 出 东西 来 , 于是 抛 错 。 所以 正确 的 做法 是 将 反 斜杠 转义 后 '.foo\\\\:bar' 再 传递 给 querySelector, 后者 在 接收 到 '.foo\\\\:bar' 这个 参数 后 , 字符串 将 两个 反 斜杠 转义 成 一个 , 然后 querySelector 前面 得到 的 一个 反 斜杠 与 冒号 结合 进行 转义 得到 正确 结果 。 也就是说 经历 两次 转义 , 一次 是 字符串 当中 , 一次 是 querySelector 解析 参数 时 。 理解 这点 后 , 可以 来看 一个 更 有趣 的 例子 了 。 比如 我们 要 选择 类 名 里面 含 反 斜杠 的 元素 。 是 的 , 我们 需要 一共 使用 四个 反 斜杠 ! 才能 正常 工作 。`` 浏览器 兼容性 目前 各 主流 浏览器 对此 API 提供 了 良好 支持 ,IE 需 8+。 详情 见 caniuse。REFERENCE> 本文 主要 参考 了 MDN 上 的 文档 document.querySelectorAlldocument.querySelectorNodeListFeel free to repost but keep the link to this page please!IE6、IE7 兼容 querySelectorAll 和 querySelector 方法 - 最终 版本 ** querySelector 和 querySelectorAll 方法 是 W3C Selectors API 规范 中 定义 的 。 他们 的 作用 是 根据 CSS 选择器 规范 , 便捷 定位 文档 中 指定 元素 。 目前 几乎 主流 浏览器 均 支持 了 他们 。 包括 IE8( 含 ) 以上 版本 、 Firefox、 Chrome、Safari、Opera。** querySelector 和 querySelectorAll 方法 很 好 用 , 可惜 IE6、IE7 不 支持 , 怎么 让 IE6、IE7 也 支持 querySelectorAll 和 querySelector 这 两个 方法 呢 , 请 看 下面 的 代码 :if (!document.querySelectorAll) { document.querySelectorAll = function (selectors) { var style = document.createElement('style'), elements = [], element; document.documentElement.firstChild.appendChild(style); document._qsa = []; style.styleSheet.cssText = selectors + '{x-qsa:expression(document.qsa && document.qsa.push(this))}'; window.scrollBy(0, 0); style.parentNode.removeChild(style); while (document._qsa.length) { element = document._qsa.shift(); element.style.removeAttribute('x-qsa'); elements.push(element); } document._qsa = null; return elements; };}if (!document.querySelector) { document.querySelector = function (selectors) { var elements = document.querySelectorAll(selectors); return (elements.length) ? elements[0] : null; };}// 用于 在 IE6 和 IE7 浏览器 中 , 支持 Element.querySelectorAll 方法 var qsaWorker = (function () { var idAllocator = 10000; function qsaWorkerShim(element, selector) { var needsID = element.id === \"\"; if (needsID) { ++idAllocator; element.id = \"__qsa\" + idAllocator; } try { return document.querySelectorAll(\"#\" + element.id + \" \" + selector); } finally { if (needsID) { element.id = \"\"; } } } function qsaWorkerWrap(element, selector) { return element.querySelectorAll(selector); } // Return the one this browser wants to use return document.createElement('div').querySelectorAll ? qsaWorkerWrap : qsaWorkerShim;})();CSS3 动画 那么 强 ,requestAnimationFrame 还有 毛线 用 ? 而 我 requestAnimationFrame 就是 为了 这个 而 出现 的 。 我 所 做 的 事情 很 简单 , 跟着 浏览器 的 绘制 走 , 如果 浏览 设备 绘制 间隔 是 16.7ms, 那 我 就 这个 间隔 绘制 ; 如果 浏览 设备 绘制 间隔 是 10ms, 我 就 10ms 绘制 。 这样 就 不会 存在 过度 绘制 的 问题 , 动画 不会 掉 帧 , 自然 流畅 的 说 > 简单 兼容 window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); };})();> 但是 呢 , 并 不是 所有 设备 的 绘制 时间 间隔 是 1000/60 ms, 以及 上面 并 木 有 cancel 相关 方法 , 所以 , 就 有 下面 这份 更 全面 的 兼容 方法 : 然后 , 我们 就 可以 以 使用 setTimeout 的 调调 使用 requestAnimationFrame 方法 啦 ,IE6 也 能 支持 哦 !(function() { var lastTime = 0; var vendors = ['webkit', 'moz']; for(var x = 0; x 接口 说明 在 Web APP 中 HTML5 也 提供 了 类似 的 接口 , 就是 DeviceMotionEvent。DeviceMotion 封装 了 运动 传感器 数据 的 事件 , 可以 获取 手机 运动 状态 下 的 运动 加速度 等 数据 。>DeviceMotionEvent 对象 属性 列表 :| 属性 | 释义 || ------ |:-------:|| event.accelaration | x(y,z): 设备 在 x(y,z) 方向 上 的 移动 加速度 值 || event.accelarationIncludingGravity | x(y,z): 考虑 了 重力 加速度 后 设备 在 x(y,z) 方向 上 的 移动 加速度 值 || event.rotationRate | alpha,beta,gamma: 设备 绕 x,y,z 轴 旋转 的 角度 |event.accelarationIncludingGravity 与 event.accelaration 的 区别 在于 前者 加入 了 重力 加速度 , 即 在 z 轴 方向 加 了 9.8, 在 x,y 方向 上 的 值 两者 相同 。 旋转 速度 rotationRate:alpha、beta、gamma 的 概念 与 DeviceOrientationEvent 一致 。> 区别 在于 :DeviceOrientationEvent 的 值 是 相对 于 初始状态 的 差值 , 只要 设备 方向 不变 , 怎么 动 都 不会 影响 数值 ;DeviceMotionEvent 是 相对 于 之前 的 某个 瞬间 值 的 差值 时间 比 , 即 变化 的 速度 , 一旦 设备 静止 则 会 恢复 为 0。 实现 方法 Shake 对象 设计 | 属性 | 值 ||-------|:------:|| SHAKE_THRESHOLD | 阈值 。 阈值 越 大 , 触发 摇晃 事件 时 手机 摇晃 的 程度 越 剧烈 || x | x 方向 的 加速 值 || y | y 方向 的 加速 值 || z | z 方向 的 加速 值 || deviceMotionHandler | 摇晃 事件 处理程序 || 方法 | 作用 ||--------|:--------:|| init | 初始化 Shake 对象 || 参数 | 值 ||-------|:----:|| threshold | 自定义 阈值 , 默认 2000|| callback | 摇晃 后 的 回调 函数 | 示例 function Shake(threshold, callback) { this.SHAKE_THRESHOLD = threshold ? threshold : 2000; // 定义 阈值 this.last_update = 0; this.x = this.y = this.z = this.lastx = this.lasty = this.last_z = 0; this.init = function() { if (window.DeviceMotionEvent) { window.addEventListener('devicemotion', this.deviceMotionHandler, false); } else { alert(' 您 的 浏览器 不 支持 DeviceMotion'); } }; var that = this; this.deviceMotionHandler = function(eventData) { var acceleration = eventData.accelerationIncludingGravity; var curTime = new Date().getTime(); if ((curTime - that.last_update) > 100) { var diffTime = curTime - that.last_update; that.last_update = curTime; that.x = acceleration.x; that.y = acceleration.y; that.z = acceleration.z; var speed = Math.abs(that.x + that.y + that.z - that.lastx - that.lasty - that.last_z) / diffTime * 10000; if (speed > that.SHAKE_THRESHOLD) { if (window.console && console.log) { console.log(\"shaked\"); } if (callback != undefined) { callback(that); } } that.last_x = that.x; that.last_y = that.y; that.last_z = that.z; } }}; 使用 手机 摇 一 摇 测试 window.onload = function() { var shake1 = new Shake(2000, function(obj) { alert(\"shaked\"); var r = document.getElementById(\"result\"); r.innerHTML = \"x:\" + obj.x + \"\"; r.innerHTML += \"y:\" + obj.y + \"\"; r.innerHTML += \"z:\" + obj.z + \"\"; }); shake1.init(); }; 当 手机 摇晃 页面 时 , 会 弹 出 shaked 的 提示 , 并且 在 页面 上 显示 摇晃 时 的 x,y,z 方向 的 加速度 值 。 扩展 应用 给 Shake 对象 的 callback 参数 可以 实现 不同 的 摇晃 目的 , 如 抽奖 。 需要 在 callback 函数 中 调用 抽奖 系统 的 接口 。// 示例 function shakeCallback(){ var odata = {name:\"drawprize\",act_id : 0000}; HBAPP.Activity.register(odata,function(json){ if(json.error == 0){ if(json.result.draw){ // 中奖 信息 //...... } } });}2. 重力 感应 重力 感应 也 是 原生 APP 中 经常 见到 的 一个 功能 , 在 Web App 中 的 应用 多见于 判断 屏幕 的 旋转 方向 , 以及 在 此基础 上 实现 的 场景 应用 , 如 控制 页面 上 物体 的 左右 移动 , 加 减速 等 。 在 Web App 中 实现 以上 的 功能 , 需要 实时 获取 屏幕 的 旋转 方向 参数 , 这些 参数 可以 从 浏览器 的 利用 HTML5 的 DeviceOrientation API 获得 。 接口 说明 当 浏览器 的 Orientation 发生变化 时 , 触发 DeviceOrientation 事件 , 并 返回 一个 DeviceOrientationEvent 对象 , 其 属性 列表 如下 :> 注 : 不同 版本 的 手机操作系统 和 浏览器 , 以及 不同 的 应用程序 中 内置 的 浏览器 对 deviceorientation 事件 的 支持 不尽相同 。 尤其 在 Android 平台 上 , 可能 会 出现 有 的 设备 正常 工作 , 有 的 则 毫无 反应 的 情况 。** 工作 原理 根据 event 对象 的 三个 方向 的 参数 来 确定 设备 的 旋转 角度 。 其中 ,alpha 的 取值 范围 是 0-360, 这个 需要 根据 设备 的 指南针 设定 情况 而 定 , 一般来说 , 设备 指向 正北 方向 时 为 0.beta 值 为 设备 绕 x 轴 旋转 的 角度 , 取值 范围 为 -180-180。gamma 取值 范围 -90-90. 这 里面 alpha 值 的 意义 并不大 , 主要 参考 beta 和 gamma 值 。 当 屏幕 从 水平 沿 y 轴向 左 倾斜 时 gamma 值 变为 负值 , 向 右 倾斜 变为 正值 。 档 屏幕 从 水平 沿 x 轴 向前 倾斜 时 beta 值 变为 正值 , 向 后 倾斜 时 变为 负值 。 所以 , 如果 我们 设定 一个 阈值 , 当 beta 和 gamma 的 绝对值 大于 这个 阈值 时 , 我们 就 认为 设备 发生 了 旋转 。 另外 根据 beta 和 gamma 的 值 来 判断 向 左 倾斜 还是 向 右 倾斜 , 以及 倾斜 的 程度 。 实现 方式 和 示例 首先 是 为 浏览器 绑定 deviceorientation 事件 和 处理程序 。//add deviceorientation event listenerif(window.DeviceOrientationEvent){ window.addEventListener('deviceorientation',DeviceOrientationHandler,false);}else{ alert(\" 您 的 浏览器 不 支持 DeviceOrientation\");} 然后 在 事件 处理程序 中 处理 相应 的 动作 function DeviceOrientationHandler(event){ var alpha = event.alpha, beta = event.beta, gamma = event.gamma; if(alpha != null || beta != null || gamma != null){ dataContainerOrientation.innerHTML = \"alpha:\" + alpha + \"beta:\" + beta + \"gamma:\" + gamma; // 判断 屏幕 方向 var html = \"\"; if( Math.abs(gamma) BETA_MAX ){ html = \" 屏幕 方向 :Portrait\"; } if( Math.abs(beta) GAMMA_MAX ){ html = \" 屏幕 方向 :Landscape\"; } var gamma_html = \"\"; if( gamma > 0 ){ gamma_html = \" 向 右 倾斜 \"; }else{ gamma_html = \" 向 左 倾斜 \"; } html += \"\"+gamma_html stage.innerHTML = html; }else{ dataContainerOrientation.innerHTML = \" 当前 浏览器 不 支持 DeviceOrientation\"; }} 这个 示例 中 展示 了 如何 利用 beta 和 gamma 值 来 展示 屏幕 的 旋转 方向 和 侧翻 方向 。 要 实现 更 精确 的 物体 判断 , 还 需要 复杂 的 算法 来 计算 。 扩展 应用 使用 DeviceOrientation API 接口 可以 实现 在 web 中 获取 手机 设备 的 屏幕 旋转 方向 参数 , 在 示例 的 基础 上 进行 改进 , 可以 扩展 到 在 屏幕 上 控制 页面 元素 的 移动 , 实现 动画 或 游戏 的 目的 。 例如 通过 调整 屏幕 的 方向 控制 页面 上 的 小球 走 迷宫 , 控制 小车 的 移动 躲避 障碍 等 。 使用 Phaser 和 HTML5 特性 检测 移动 设备 旋转 重力 方向 HTML5 中 包含 一个 帮助 检测 device orientation 的 特性 , 使用 这个 特性 可以 在 移动 设备 浏览器 中 判断 用户 设备 的 旋转 重力 方向 。 基本知识 :Alpha, Beta, Gamma 角度 旋转 当 用户 旋转 手机 的 时候 ,HTML5 中 定义 了 三个 轴 方向 的 旋转 , 如下 : 上 图 可以 看 考 , 分别 是 z,x,y 轴 , 对应 分别 是 :Alpha,Beta,Gamma, 下面 图 将 更 清楚 的 展示 :1. Alpha 上 图 是 Alpha 旋转 , 围绕 Z 轴 旋转 ( 绿 线 旋转 方向 , 水平 )2. Beta 上 图 是 Beta 旋转 , 围绕 X 轴 旋转 ( 绿 线 旋转 方向 , 前后 )3. gamma 上 图 是 gamma 旋转 , 围绕 Y 轴 旋转 ( 绿 线 旋转 方向 , 左右 ) 了解 了 基本 几个 方向 的 旋转 , 接下来 介绍 一下 相关 的 方法 :window.addEventListener(“deviceorientation”, handleOrientation); 在 HTML5 中 使用 以上 事件 监听 设备 方向 变化 。function handleOrientation(event) {var absolute = event.absolute;var alpha = event.alpha;var beta = event.beta;var gamma = event.gamma;} 以上 在 定义 的 监听 方法 中 通过 event 参数 获取 设备 的 对应 Alpha, Beta 和 Gamma 角度 。 参数 定义 如下 :DeviceOrientationEvent.absoluteDeviceOrientationEvent.alphaDeviceOrientationEvent.betaDeviceOrientationEvent.gamma 其中 相关 值 :alpha : 0 到 360 度 Beta : -180 到 180 度 Gamma : -90 到 90 度 接下来 为了 验证 HTML5 这个 特性 , 我们 使用 Phaser 来 制作 一个 简答 的 小游戏 : 首先 是 导入 Phaser 类库 `` 然后 定义 HTML 代码 中 游戏 的 容器 元素 :`` 接下来 使用 Phaser 的 游戏类 生成 游戏 :var game = new Phaser.Game(300,400,Phaser.CANVAS,‘gamezone’,{preload:preload , create:create ,update:update }); 下面 是 具体方法 :/* 定义 预 加载 方法 , 图片 , 声音 等等 */function preload(){game.load.image(‘imagemoveing’, ‘http://www.gbtags.com/gb/laitu/50×50&text= 图片 移动 /DDDDDD/DDDDDD’);// 了解 如何 使用 来 图 工具 , 请 移步 至 :http://www.gbtags.com/gb/gblaitu.htm}/* 定义 游戏 创建 方法 */var dogsprite,betadirection=0,gammadirection=0;function create(){// 这里 添加 图片 并且 居中 显示 到 屏幕 上 dogsprite = game.add.sprite(game.world.centerX, game.world.centerY , ‘imagemoveing’);dogsprite.anchor.set(0.5);// 启动 并 添加 物理 效果 game.physics.startSystem(Phaser.Physics.ARCADE); // 这里 选择 使用 的 物理 系统 ,Phaser.Physics.ARCADE 是 缺省值 game.physics.arcade.enable(dogsprite);// 保证 dogsprite 拥有 物理 特性 dogsprite.body.velocity.set(30);}function update(){// 移动游戏 中 的 方块 图片 元素 逻辑 } 最后 执行 设备 方向 检测 , 这里 只 检测 x,y 轴 , 你 向 某个 方向 偏移 设备 , 则 获取 偏移量 :function deviceOrientationListener(event) {betadirection = Math.round(event.beta);gammadirection = Math.round(event.gamma);}if (window.DeviceOrientationEvent) {window.addEventListener(“deviceorientation”, deviceOrientationListener);} else {alert(“ 您 使用 的 浏览器 不 支持 Device Orientation 特性 ”);} 最后 , 在 Phaser 的 update 方法 中 , 根据 偏移量 来 计算 移动 速度 和 方向 , 如下 :function update(){var speed = 10*(Math.abs(betadirection)+Math.abs(gammadirection));if(betadirection0){game.physics.arcade.moveToXY(dogsprite, 300, 0, speed);}else if(betadirection>0&&gammadirection>0){game.physics.arcade.moveToXY(dogsprite, 300, 400, speed);}else if(betadirection>0&&gammadirectionNote that \"orientationchange\" and screen.orientation are unprefixed in the following> 监听 orientationchangewindow.addEventListener(\"orientationchange\", function() { alert(\"the orientation of the device is now \" + screen.orientation.angle);}); // 判断 横 屏 竖 屏 function checkDirection() { if (document.documentElement.clientHeight >= document.documentElement.clientWidth) { return \"portrait\"; } else { return \"landscape\"; }}function orientNotice() { var orientLayer = document.getElementById(\"orientLayer\"); var orient = checkDirection(); if (orient == \"portrait\") { orientLayer.style.display = \"none\"; } else { orientLayer.style.display = \"block\"; }}function initOrientState() { var strVar = \"\"; strVar += \"\\n\"; strVar += \"\\n\"; strVar += \"\\n\"; strVar += \" \\n\"; strVar += \" \\n\"; strVar += \"\\n\"; strVar += \" 为了 更好 的 体验 , 请 使用 竖 屏 浏览 \\n\"; strVar += \" \\n\"; strVar += \"\\n\"; $(\"body\").append(strVar); orientNotice(); window.addEventListener(\"onorientationchange\" in window ? \"orientationchange\" : \"resize\", function () { // if (window.orientation === 90 || window.orientation === -90) { // console.log('cross') // } else { // console.log('vertical') // } setTimeout(orientNotice, 200); })}/* screen orient 屏幕 方向 */@keyframes rotation { 10% { transform: rotate(90deg); -webkit-transform: rotate(90deg); -webkit-transform: rotate(90deg) } 50% { transform: rotate(0); -webkit-transform: rotate(0); -ms-transform: rotate(0) } 60% { transform: rotate(0); -webkit-transform: rotate(0); -ms-transform: rotate(0) } 90% { transform: rotate(90deg); -webkit-transform: rotate(90deg); -ms-transform: rotate(90deg) } 100% { transform: rotate(90deg); -webkit-transform: rotate(90deg); -ms-transform: rotate(90deg) } } .mod-orient-layer { display: none; position: fixed; height: 100%; width: 100%; left: 0; top: 0; right: 0; bottom: 0; background: #000; z-index: 9997}.mod-orient-layer__content { position: absolute; width: 100%; top: 45%; margin-top: -75px; text-align: center}.mod-orient-layer__icon-orient { display: inline-block; width: 67px; height: 109px; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIYAAADaCAMAAABU68ovAAAAXVBMVEUAAAD29vb////x8fH////////x8fH5+fn29vby8vL////5+fn39/f6+vr////x8fH////////+/v7////09PT////x8fH39/f////////////////////x8fH///+WLTLGAAAAHXRSTlMAIpML+gb4ZhHWn1c2gvHBvq1uKJcC6k8b187lQ9yhhboAAAQYSURBVHja7d3blpowFIDhTUIAOchZDkre/zE7ycySrbUUpsRN2/1fzO18KzEqxEVgTiZNfgmmtxRc8iaR8HNe8x4BtjQePKayYCIoyBSgvNNE1AkNSHqZyLqk97EgUCCHBzZ5mkg7ScvIJuIyOyXBRFxgpqWZyGsAZLB1KjsJi8nutHU4JCRbFRH8tmirI9k8Jx2sqNs8K/m0LQkrktO2crgcgXGB4AiTEsB0hJfo9MGgX7CGcYiYwQxmMOOvZwRhBG8tCoMXjBDeXvWCEcHbi14wgCBmMIMZzGAGM5jxETNwzMAxA8cMHDNwzMAxA8cMHDNwzMAxA8cMHDNwzMAxY6E2rUQxnH2tz9cirlJFwFBJedaPnUv0M7++egPDE8iAJcIDmxwH5wwv9vUviw2kLbVO3TJU5uul/EyB0FoLp4x60PdGUd3qPurrWyjGGTc05u+1dcgI7/+tCCPARWGhH7o5Y7RCf+bH9ctXLp6v2BVDxfqz0oPXeSVaNtINo/1SXDv4dck8IIkbhtC2ol+iouEonTBCbYvVMnXOjxww6s/RFrBUpXHh/gw1rHj5d/qhYn9Gpk2FWh6xRBRX5Oj3Znh2Sq49/L6+y8pB26q9GbE2dbA2mVbx6I+7MfBglLCttm73ZQi7AD3iL4HqjFYJHSPRppqaUaJ3ATpGa+ckpGak2hRRMyqjGMkvl+xyFeSMwjAqcsZgGDdyhl0oNTnDN4yenJGZFGxNChP5/Y3efh6SM2rDOJMzboYxkDMqwyjIGcIw6F+io2FU1IxIm1JqRmgXSkvNKNCXeTpGrU0JNSO2c6LIGPgCS8AuDHz9ta0SXWDtxoDRH+MqlbC2Dt2G2JFRadtQZt2qq/orGowdGb2euxYiqWEpVWhTBnszoNAPdStuQwxqf0aocdWKW4Z+DfszIh8pxJqbuCE4YAC+4bm0evtipjpgJHeFnyyt1Ku2xa0bhjxr27p75rECNwyI9ZwvXkHq+7aTaMEV44YYy/spfgjgjNHaWW+GeUhGEX7tLlVinIFDDSgnOwhi1V6bU0b6tVS9eAERe863g4dRrtiHdc6o+nn5vtyVVgR79Cqt4uL6gfHPQyGqtP2vf7HADGbcYwaOGThm4JiBYwaOGThm4JiBYwaOGThm4JiBYwaOGThm4JiBYwaOGThm4JjhtOM+J/AgT008yDMkN/dPP9hzS8zAMQN3OEYeekp5YU7KOKXwVXqiY+QS7smcinGKABWdiBgpPJTSMHJ4KidhhPBUSMLw4CmPhKHgKUXCkHsygum71ftNSgCX6bsl8FQyfbcL5EdYsDk0R3j7aiA5wpt5AjKg/2gLJEBD/0Hf2OOf/vRrj6z/7GtP4B3nMKyjHA12kIPSjnJs3FEO0TvKkYJHOWCR+rjJH0Vn6fI5PjNbAAAAAElFTkSuQmCC'); transform: rotate(90deg); -webkit-transform: rotate(90deg); -webkit-animation: rotation infinite 1.5s ease-in-out; animation: rotation infinite 1.5s ease-in-out; -webkit-background-size: 67px; background-size: 67px}.mod-orient-layer__desc { margin-top: 20px; font-size: 15px; color: #fff}.mod-orient-layer__desc { margin-top: 20px; font-size: 15px; color: #fff}HTML5 - 地理 定位 Geolocationnavigator.geolocation.getCurrentPosition(function(position){console.log(position.coords.latitute,position.coords.longtitude)}) 完美 解决 window.navigator.geolocation.getCurrentPosition, 在 IOS10 系统 中 无法 定位问题 1、 将 网站 的 http 设置 为 Https。 2、 通过 第三方 解决 , 这 也 是 我 目前 使用 的 方法 。 // 如 使用 百度 定位 HTML5 的 popstate 如何 玩转 浏览器 历史记录 一 、popstate 用来 做 什么 的 ? 简而言之 就是 HTML5 新增 的 用来 控制 浏览器 历史记录 的 api。 二 、 过去 如何 操纵 浏览器 历史记录 ?window.history 对象 , 该 对象 上 包含 有 length 和 state 的 两个 值 , 在 它 的 proto 上 继承 有 back、forward、go 等 几个 功能 函数 在 popstate 之前 , 我们 可以 利用 back、forward、go 对 history 进行 后退 和 前进 操作 。 例如 :history.back(); ( 后退 一步 , 使用 history.go(-1) 也 可 实现 后退 效果 ) 弊端 : 只能 操作 前进 后退 , 但是 无法控制 前进 后 要 去 哪 ,history.length 都 只 会 维持 原来 的 状态 三 、popstate 的 怎么 用 ?HTML5 的 新 API 扩展 了 window.history, 使 历史记录 点 更加 开放 了 。 可以 存储 当前 历史记录 点 pushState、 替换 当前 历史记录 点 replaceState、 监听 历史记录 点 popstate。pushState、replaceState 两者 用法 差不多 。 使用 方法 :history.pushState(data,title,url);// 其中 第一个 参数 data 是 给 state 的 值 ; 第二个 参数 title 为 页面 的 标题 , 但 当前 所有 浏览器 都 忽略 这个 参数 , 传 个 空 字符串 就 好 ; 第三个 参数 url 是 你 想要 去 的 链接 ;replaceState 用法 类似 , 例如 :history.replaceState(\" 首页 \",\"\",location.href+ \"#news\"); 一 、 简单 介绍 history 中 的 操作 1.window.history.back(), 后退 2.window.history.forward(), 前进 3.window.history.go(num), 前进 或 后退 指定 数量 历史记录 4.window.history.pushState(state, title, utl), 在 页面 中 创建 一个 history 实体 。 直接 添加 到 历史记录 中 。 参数 : state: 存储 一个 对象 , 可以 添加 相关 信息 , 可以 使用 history.state 读取 其中 的 内容 。 title: 历史记录 的 标题 。 url: 创建 的 历史记录 的 链接 。 进行 历史记录 操作 时会 跳转 到 该 链接 。5.window.history.replaceState(), 修改 当前 的 history 实体 。6.popstate 事件 ,history 实体 改变 时 触发 的 事件 。7.window.history.state, 会 获得 history 实体 中 的 state 对象 。 注意事项 > 两者 区别 :pushState 会 改变 history.length, 而 replaceState 不 改变 history.length>1. 每次 返回 都 会 消耗 一个 history 实体 , 若 用户 选择 取消 离开 , 则 需要 继续 pushState 一个 实体 >2.pushState 只能 一个 实体 , 多个 实体 返回 会 出错 。 使用 window.history.state 查询 是否 存在 添加 的 实体 。 图解 用 HTML5 的 popstate 如何 玩转 浏览器 历史记录 新闻 音乐 var locationHref = location.href; document.addEventListener(\"click\", function (event) { var target = event.target; if (target.className == \"js-news\") { history.pushState(\" 首页 \", \"\", locationHref + \"#news\"); } else if (target.className == \"js-music\") { history.pushState(\" 音乐 \", \"\", locationHref + \"#music\"); } }); /* document.addEventListener(\"click\",function(event){ var target = event.target; if(target.className == \"js-news\"){ history.replaceState(\" 首页 \",\"\",locationHref + \"#news\"); }else if(target.className == \"js-music\"){ history.replaceState(\" 音乐 \",\"\",locationHref + \"#music\"); } });*/ window.addEventListener(\"popstate\", function () { console.log(history.state); })// 例如 modal 页 操作 , 为了 实现 后退 效果 , 可以 pushState;//1 当前 页面 ajax 局部 刷新 , 或者 打开 modal 页 ; 插入 一条 page 记录 history.pushState(\"null\",'',location.href.split(\"#\")[0]+'#detail');//2 监听 页面 回退 或 前进 , 达到 路径 跳转 效果 window.addEventListener(\"popstate\", function() { var currentState = history.state; location.reload(); });Html5 workers 后台 运行 jsHTML5 Web Workers 是 为 网页 脚本 提供 了 一种 能 在 后台 进程 中 运行 的 方法 。 当 创建 WoOer 对象 后 ,WebwbrkerS 就 可以 通过 postMessage 方法 向 任务 池 发送 任务 请求 , 执行 完 之后 再 通过 postMessage 返回 消息 给 创建者 指定 的 事件 处理程序 , 然后 通过 onmessage 捕获 返回 消息 , 实现 前后 台 数据 的 交互 。Web Workers 应用 场景 在 Web 应用程序 中 ,Web WoOers 是 一项 后台 处理 技术 。 在此之前 使用 JavaScript 创建 的 W 曲 程序 中 , 因为 所有 的 处理 都 是 在 单线程 内 执行 , 所以 如果 脚本 所 需 运行 时间 太 长 , 程序界面 会长 时间 处于 停止 响应 状态 , 甚至 当 等待时间 超出 一定 的 限度 , 浏览器 会 提示 脚本 运行 时间 过长 需要 中断 正在 执行 的 处理 。 为了 解决 这个 问题 ,HTML5 新增 了 一个 Web WorkersAPI。 使用 这个 API, 用户 可以 很 容易 地 创建 在 后台 运行 的 线程 , 这个 线程 被 称为 Worker, 如果 将 可能 耗费 较长时间 的 处理 交给 后台 执行 , 则 对 用户 在 前台 页面 中 执行 的 操作 没有 影响 。 尽管 Web Workers 功能强大 , 但 也 不是 万能 的 , 例如 , 在 Web Workers 中 执行 的 脚本 不能 访问 该 页面 的 window 对象 , 因此 Web Workers 不能 直接 访问 Web 页面 和 DOM API, 虽然 Web Workers 不会 导致 浏览器 UI 停止 响应 , 但是 仍然 会 消耗 CPU 周期 , 导致系统 反应速度 变慢 。 如果 开发人员 创建 的 Web 应用程序 需要 执行 一些 后台 数据处理 , 但 又 不 希望 这些 数据处理 任务 影响 Web 页面 本身 的 交互性 , 那么 可以 通过 Web Workers 生成 一个 WoOer 去 执行 数据处理 任务 。 同时 添加 一个 事件 监听器 进行 监听 , 并 与 之 进行 数据 交互 。 Web Workers 的 另 一个 用途 是 可以 监听 由 后台 服务器 广播 的 消息 , 收到 后台 服务器 的 消息 后 , 将 其 显示 在 Web 页面 上 。 这种 与 后台 服务器 对话 的 场景 ,Web Workers 可能 会 使用 到 Web Sockets 或 Server—Sent 事件 。 Web Workers 接口 可以 创建 真正 的 系统 级别 的 进程 , 还 可以 使用 XMLHttpRequest 来 处理 I/O, 无论 responseXML 和 channel 属性 是否 为 null。 使用 它 可以 很 容易 设计 并发 操作 效果 , 这 将 会 很 有趣 。 例如 , 在 做 网站 下载 的 时候 使用 Worker, 或者 使用 Worker 实现 处理 扩展 功能 。 注意 : 后台 进程 ( 包括 Web Workers 进程 ) 不能 对 DOM 进行 操作 。 如果 希望 后台程序 处理 的 结果 能够 改变 DOM, 只能 通过 返回 消息 给 创建者 的 回调 函数 进行 处理 。Web Workers 能够 为 用户 做 些 什么 ? 加载 一个 JavaScript 文件 , 进行 大量 的 复杂 计算 , 而 不 挂 起 主 进程 , 并 通过 postMessage 和 onMessage 进行 通信 。 可以 在 WoOer 中 通过 importScripts(url) 方法 加载 JavaScript 脚本 文件 。 可以 使用 setTimeout()、clearTimeout()、setInterval() 和 clearInterval()。 可以 使用 XMLHttpRequest 进行 异步 请求 。 可以 访问 navigator 的 部分 属性 。 可以 使用 JavaScript 核心 对象 。web Workers 的 局限性 : 不能 跨 域 加载 JavaScriot。 前端 项目 优化 前端 是 庞大 的 , 包括 HTML、 CSS、 Javascript、Image 、Flash 等等 各种各样 的 资源 。 前端 优化 是 复杂 的 , 针对 方方面面 的 资源 都 有 不同 的 方式 。 那么 , 前端 优化 的 目的 是 什么 ? 从 用户 角度 而言 , 优化 能够 让 页面 加载 得 更 快 、 对 用户 的 操作 响应 得 更 及时 , 能够 给 用户 提供 更为 友好 的 体验 。 从 服务商 角度 而言 , 优化 能够 减少 页面 请求 数 、 或者 减小 请求 所 占 带宽 , 能够 节省 可观 的 资源 。 总之 , 恰当 的 优化 不仅 能够 改善 站点 的 用户 体验 并且 能够 节省 相当 的 资源 利用 。 前端 优化 的 途径 有 很多 , 按 粒度 大致 可以 分为 两类 , 第一类 是 页面 级别 的 优化 , 例如 HTTP 请求 数 、 脚本 的 无 阻塞 加载 、 内联 脚本 的 位置 优化 等 ; 第二类 则 是 代码 级别 的 优化 , 例如 Javascript 中 的 DOM 操作 优化 、CSS 选择符 优化 、 图片 优化 以及 HTML 结构 优化 等等 。 另外 , 本着 提高 投入产出 比 的 目的 , 后 文 提到 的 各种 优化 策略 大致 按照 投入产出 比 从 大 到 小 的 顺序排列 。 一页 面 级 优化 >1. 减少 HTTP 请求 数 (1). 从 设计 实现 层面 简化 页面 (2). 合理 设置 HTTP 缓存 (HTTP Header 中 的 Expires 设置 一个 很 长 的 过期 头 ; 变化 不 频繁 而 又 可能 会 变 的 资源 可以 使用 Last-Modifed 来 做 请求 验证 。 尽可能 的 让 资源 能够 在 缓存 中 待 得 更 久 。) (3). 资源 合并 与 压缩 (4). CSS Sprites (5). Inline Images (6). Lazy Load Images>2. 将 外部 脚本 置 底 ( 将 脚本 内容 在 页面 信息内容 加载 后 再 加载 )>3. 异步 执行 inline 脚本 ( 其实 原理 和 上面 是 一样 , 保证 脚本 在 页面 内容 后面 加载 。)>4. Lazy Load Javascript>5. 将 CSS 放在 HEAD 中 >6. 异步 请求 Callback( 就是 将 一些 行为 样式 提取 出来 , 慢慢 的 加载 信息 的 内容 )>7. 减少 不必要 的 HTTP 跳转 >8. 避免 重复 的 资源 请求 二 、 代码 级 优化 >1. Javascript (1).DOM DOM 操作 应该 是 脚本 中 最 耗 性能 的 一类 操作 , 例如 增加 、 修改 、 删除 DOM 元素 或者 对 DOM 集合 进行 操作 。 如果 脚本 中 包含 了 大量 的 DOM 操作 则 需要 注意 以下几点 : a. HTML Collection(HTML 收集器 , 返回 的 是 一个 数组 内容 信息 ); 在 脚本 中 document.images、document.forms 、getElementsByTagName() 返回 的 都 是 HTMLCollection 类型 的 集合 b. Reflow & Repaint ( 除了 上面 一点 之外 , DOM 操作 还 需要 考虑 浏览器 的 Reflow 和 Repaint) (2). 慎用 with (3). 避免 使用 eval 和 Function eval 函数 效率 特别 低 , 由于 事先 无法 知晓 传给 eval 的 字符串 中 的 内容 (4). 减少 作用域 链 查找 ( 这方面 设计 到 一些 内容 的 相关 问题 ) 前 文 谈到 了 作用域 链 查找 问题 , 这 一点 在 循环 中 是 尤其 需要 注意 的 问题 。 如果 在 循环 中 需要 访问 非 本 作用域 下 的 变量 时 请 在 遍历 之前 用 局部变量 缓存 该 变量 , 并 在 遍历 结束 后 再 重写 那个 变量 , 这 一点 对 全局变量 尤其 重要 , 因为 全局变量 处于 作用域 链 的 最 顶端 , 访问 时 的 查找 次数 是 最 多 的 。 / 低效率 写法 / // 全局变量 var globalVar = 1; function myCallback(info){ for( var i = 100000; i--;){ // 每次 访问 globalVar 都 需要 查找 到 作用域 链 最 顶端 , 本例 中 需要 访问 100000 次 globalVar += i; } } / 更 高效 写法 / // 全局变量 var globalVar = 1; function myCallback(info){ // 局部变量 缓存 全局变量 var localVar = globalVar; for( var i = 100000; i--;){ // 访问 局部变量 是 最快 的 localVar += i; } // 本例 中 只 需要 访问 2 次 全局变量 在 函数 中 只 需要 将 globalVar 中 内容 的 值 赋 给 localVar 中 区 globalVar = localVar; } 此外 , 要 减少 作用域 链 查找 还 应该 减少 闭 包 的 使用 。 (5). 数据 访问 Javascript 中 的 数据 访问 包括 直接 量 ( 字符串 、 正则表达式 )、 变量 、 对象 属性 以及 数组 , 其中 对 直接 量 和 局部变量 的 访问 是 最快 的 , 对 对象 属性 以及 数组 的 访问 需要 更 大 的 开销 。 (6). 字符串 拼接 >2.CSS 选择符 ( 浏览器 对 选择符 的 解析 是从 右 往 左 进行 的 )>3.HTML>4. 图片 压缩 DOM 结构 timeline repaint( 重 绘 ) 与 reflow( 回流 )>reflow: 当 render 树 中 的 一部分 或者 全部 因为 大小 边 距 等 问题 发生 改变 而 需要 重建 的 过程 叫做 回流 .>repaint: 当 元素 的 一部分 属性 发生变化 , 如 外观 背景色 不会 引起 布局 变化 而 需要 重新 渲染 的 过程 叫做 重 绘 。relow 一定 会 引起 repaint,repaint 不 一定 引起 reflow; 参考 : 回流 (reflow) 与 重 绘 (repaint)> 如何 避免 ? 但是 尽管 浏览器 挺 机智 地 帮 我们 优化 了 代码 , 我们 自己 作 死 也 是 没 救 的 , 比如 你 去 请求 offsetTop, offsetLeft, offsetWidth, offsetHeightscrollTop/Left/Width/HeightclientTop/Left/Width/Heightwidth,height 请求 了 getComputedStyle(), 或者 IE 的 currentStyle 浏览器 为了 给 你 返回 一个 比较 精确 的 答案 , 他 会 提前 flush 队列 , 因为 队列 中 可能 会 有 影响 这些 值 的 操作 。 所以 我们 可以 做 的 是 :1. 将 那些 改变 样式 的 操作 集合 在 一次 完事 , 直接 改变 className 或者 cssText2. 让 要 操作 的 元素 进行 离线 处理 , 处理 完事 以后 再 一起 更新 (1) 使用 DocumentFragment 进行 缓存 操作 , 引发 一次 回流 和 重 绘 课外 延伸 :DocumentFragment 节点 不 属于 文档 树 , 继承 的 parentNode 属性 总是 null。 不过 它 有 一种 特殊 的 行为 , 该 行为 使得 它 非常 有用 , 即 当 请求 把 一个 DocumentFragment 节点 插入 文档 树 时 , 插入 的 不是 DocumentFragment 自身 , 而是 它 的 所有 子孙 节点 。 这 使得 DocumentFragment 成 了 有用 的 占位 符 , 暂时 存放 那些 一次 插入 文档 的 节点 。 它 还 有利于 实现 文档 的 剪切 、 复制 和 粘贴 操作 。 其实 他 就是 一个 游离 在 DOM 树 外面 的 容器 , 所以 你 在 把 它 插入 文档 节点 之前 , 随便 给 他 增删 节点 都 不会 引起 回流 (2) 使用 display:none, 只 引发 两次 回流 和 重 绘 。 道理 跟 上面 的 一样 。 因为 display:none 的 元素 不会 出现 在 render 树 (3) 使用 cloneNode 和 replaceChild 技术 , 引发 一次 回流 和 重 绘 ( 这 条 其实 没 太 明白 )3. 不要 经常 访问 会 引起 浏览器 flush 队列 的 属性 , 非 要 高频 访问 的话 建议 缓存 到 变量 ;4. 将 需要 多次 重排 的 元素 ,position 属性 设 为 absolute 或 fixed, 这样 此 元素 就 脱离 了 文档 流 , 它 的 变化 不会 影响 到 其他 元素 。 例如 有 动画 效果 的 元素 就 最好 设置 为 绝对 定位 ;5. 尽量 不要 使用 表格 布局 , 如果 没有 定 宽 表格 一列 的 宽度 由 最 宽 的 一列 决定 , 那么 很 可能 在 最后 一行 的 宽度 超出 之前 的 列 宽 , 引起 整体 回流 造成 table 可能 需要 多次 计算 才能 确定 好 其 在 渲染 树 中 节点 的 属性 , 通常 要 花 3 倍 于 同等 元素 的 时间 。","title":"HTML5 整理 总结 ","oriTitle":"HTML5整理总结"},{"uri":"/posts/summary-javascript-term","tags":["Javascript"],"content":"[toc] 为什么 在 编写 代码 的 时候 要 使用 unicode 来 表示 中文 ? 看 别人 的 代码 , 有 这样 的 片段 。setText(\"\\u5BFC\\u5165\\u8DEF\\u5F84\") 为什么 不 直接 用 中文 写 出来 , 而 使用 unicode 表示 。 两种 方式 有 什么 区别 有 什么 利弊 ?1. 第一种 也 是 \" 国际化 \" 的 内容 , 一般 都 定义 在 资源 文件 里面 , 好处 是 , 在 任何 环境 下 , 他 都 不会 输出 乱码 .2. 第二种 , 在 一般 的 情况 下 , 如 : 我们 国内 的 使用 环境 是 没有 问题 的 , 但是 如 国外 的 网站 访问 , 可能 会 有 乱码 . 不过 一般 日本 人 喜欢 用 第一种 方式 . 但是 工作效率 低 , 他们 的 想法 就是 : 宁可 在 实现 过程 中 繁琐 , 不 在 应用 过程 中 找麻烦 . 而 我们 国内 的 一般 都 直接 用 第二种 了 , 我们 的 想法 是 : 先 实现 了 功能 , 有 问题 再 改 unicode 在 字体 中 应用 : 数值 Number 安全 整数 和 Number.isSafeInteger()JavaScript 能够 准确 表示 的 整数 范围 在 -2^53 到 2^53 之间 ( 不 含 两个 端点 ), 超过 这个 范围 , 无法 精确 表示 这个 值 。Math.pow(2, 53) // 90071992547409929007199254740992 // 90071992547409929007199254740993 // 9007199254740992Math.pow(2, 53) === Math.pow(2, 53) + 1// true 上面 代码 中 , 超出 2 的 53 次方 之后 , 一个 数 就 不 精确 了 。ES6 引入 了 Number.MAXSAFEINTEGER 和 Number.MINSAFEINTEGER 这 两个 常量 , 用来 表示 这个 范围 的 上 下限 。 单精度 浮点数 双 精度 浮点数 ES6 Math.fround 方法 返回 一个 数 的 单精度 浮点数 形式 。 对于 没有 部署 这个 方法 的 环境 , 可以 用 下面 的 代码 模拟 。Math.fround(1.337) // 1.3370000123977661Math.fround = Math.fround || function(x) { return new Float32Array([x])[0];};1、 单精度 浮点数 (Single) 用来 表示 带有 小数 部分 的 实数 , 一般 用于 科学计算 。 占用 4 个 字节 (32 位 ) 存储空间 , 包括 符号 位 1 位 , 阶 码 8 位 , 尾数 23 位 。 其 数值 范 为 -3.4E38~3.4E38, 单精度 浮点数 最 多 有 7 位 十进制 有效数字 , 单精度 浮点数 的 指数 用 “E” 或 “e” 表示 。 单精度 浮点数 有 多种 表示 形式 :±n.n( 小数 形式 ) ±n E ±m( 指数 形式 ) ±n.n E ±m ( 指数 形式 ) 如果 某个 数 的 有效数字 位数 超过 7 位 , 当 把 它 定义 为 单精度 变量 时 , 超出 的 部分 会 自动 四舍五入 。2、 双 精度 浮点数 (double) 用 8 个 字节 (64 位 ) 存储空间 , 包括 符号 位 1 位 , 阶 码 11 位 , 尾数 52 位 。 平方根 , 自然对数 1. 平方根 平方根 , 又 叫 二次方 根 , 表示 为 〔√ ̄〕, 其中 属于 非 负数 的 平方根 称之为 算术 平方根 。 一个 正数 有 两个 实 平方根 , 它们 互为 相反数 ;0 只有 一个 平方根 , 就是 0 本身 ; 负数 有 两个 共轭 的 纯 虚 平方根 。 一般 地 ,“√ ̄” 仅 用来 表示 算术 平方根 , 即 非 负 的 平方根 。 如 :√16=4。Math.sqrt() 返回 数字 的 平方根 Math.sqrt('16') // 4Math.cbrt() 计算 一个 数 的 立方根 Math.cbrt('8') // 22. 自然对数 Math.log() 可 返回 一个 数 的 自然对数 。Math.log(2.7183) //1.0000066849139877 自然对数 : 以 常数 e 为 底数 的 对数 叫做 自然对数 , 记 作 lnN(N>0)。 自然对数 在 物理学 , 生物学 等 自然科学 中 有 重要 的 意义 。e 是 一个 无限 不 循环小数 , 其 值 约等于 2.718281828459…, 它 是 一个 超越数 。 对数 , 是 一个 数学 名词 , 也 是 一种 数学方法 ! 如果 a 的 n 次方 等于 b(a 大于 0, 且 a 不 等于 1), 那么 数 n 叫做 以 a 为 底 b 的 对数 , 记 做 n=loga 的 b 次方 , 也 可以 说 log(a)b=n。 其中 ,a 叫做 “ 底数 ”,b 叫做 “ 真 数 ”,n 叫做 “ 以 a 为 底 b 的 对数 ”。 数学 表示法 自然对数 的 一般 表示 方法 为 lnx。 数学 中 也 常见 以 logx 表示 自然对数 。 若 为了 避免 与 基 为 10 的 常用对数 lgx 混淆 , 可用 “ 全 写 ”㏒ex。[1]e 的 级数 展开式 易 证明 : 函数 展开 为 x 的 幂级数 (Maclaurin 级数 ) 是 项目 B/S web 项目 B/S 指 的 是 browser/server, 就是说 是 浏览器 与 服务端 模式 ,WEB 开发 基本 都 是 基于 这种 模式 的 B/S 系统 , 说 白点 就是 Web 开发 或 网站 开发 吧 。 三 大 主流 技术 及 基本特征 1、asp.net (+sql server) 基本 运行 在 widows 平台 2、php (+mysql) 跨平台 3、jsp (+oracle) 安全性 要求 高 的 站点 javascript 核心 javascript 同步 和 异步 的 区别 与 实现 方式 javascript 语言 是 单线程 机制 。 所谓 单线程 就是 按 次序 执行 , 执行 完 一个 任务 再 执行 下 一个 。 对于 浏览器 来说 , 也 就是 无法 在 渲染 页面 的 同时 执行 代码 。 单线程 机制 的 优点 在于 实现 起来 较为简单 , 运行 环境 相对 简单 。 缺点 在于 , 如果 中间 有 任务 需要 响应 时间 过长 , 经常 会 导致 页面 加载 错误 或者 浏览器 无 响应 的 状况 。 这 就是 所谓 的 “ 同步 模式 ”, 程序执行 顺序 与 任务 排列 顺序 一致 。 对于 浏览器 来说 , 同步 模式 效率 较 低 , 耗时 长 的 任务 都 应该 使用 异步 模式 ; 而 在 服务器端 , 异步 模式 则 是 唯一 的 模式 , 如果 采用 同步 模式 个人 认为 服务器 很快 就 会 出现 12306 在 高峰期 的 表现 。。。。 异步 模式 的 四种 方式 :1. 回调 函数 callback 所谓 回调 函数 , 就是 将 函数 作为 参数 传到 需要 回调 的 函数 内部 再 执行 。 典型 的 例子 就是 发送 ajax 请求 。 例如 : $.ajax({ async: false, cache: false, dataType: 'json', url: \"url\", success: function(data) { console.log('success'); }, error: function(data) { console.log('error'); } }) 当 发送 ajax 请求 后 , 等待 回应 的 过程 不会 堵塞 程序运行 , 耗时 的 操作 相当于 延后 执行 。 回调 函数 的 优点 在于 简单 , 容易 理解 , 但是 可读性 较差 , 耦合度 较 高 , 不 易于 维护 。2. 事件驱动 javascript 可以 称之为 是 基于 对象 的 语言 , 而 基于 对象 的 基本特征 就是 事件驱动 (Event-Driven)。 事件驱动 , 指 的 是 由 鼠标 和 热键 的 动作 引发 的 一连串 的 程序 操作 。 例如 , 为 页面 上 的 某个 绑定 click 事件 ;$('#btn').onclick(function(){ console.log('click button');}); 绑定 事件 相当于 在 元素 上 进行 监听 , 是否 执行 注册 的 事件 代码 取决于 事件 是否 发生 。 优点 在于 容易 理解 , 一个 元素 上 可以 绑定 多个 事件 , 有利于 实现 模块化 ; 但是 缺点 在于 称为 事件驱动 的 模型 后 , 流程 不 清晰 。3. 发布 / 订阅 发布 订阅 模式 (publish-subscribe pattern) 又 称为 观察者 模式 (Observer pattern)。 该 模式 中 , 有 两类 对象 : 观察者 和 目标 对象 。 目标 对象 中 存在 着 一份 观察者 的 列表 , 当 目标 对象 的 状态 发生 改变 时 , 主动 通知 观察者 , 从而 建立 一种 发布 / 订阅 的 关系 。jquery 有 相关 的 插件 , 在 这 不是 重点 不 细说 了 。。。。 回头 写 个 实现 贴上来 4.promise 模式 promise 对象 是 CommonJS 工作组 提供 的 一种 规范 , 用于 异步 编程 的 统一 接口 。promise 对象 通常 实现 一种 then 的 方法 , 用来 在 注册 状态 发生 改变 时 作为 对应 的 回调 函数 。promise 模式 在 任何时刻 都 处于 以下 三种 状态 之一 : 未 完成 (unfulfilled)、 已 完成 (resolved) 和 拒绝 (rejected)。 以 CommonJS Promise/A 标准 为 例 ,promise 对象 上 的 then 方法 负责 添加 针对 已 完成 和 拒绝 状态 下 的 处理函数 。then 方法 会 返回 另 一个 promise 对象 , 以便 于 形成 promise 管道 , 这种 返回 promise 对象 的 方式 能够 支持 开发人员 把 异步 操作 串联 起来 , 如 then(resolvedHandler, rejectedHandler); 。resolvedHandler 回调 函数 在 promise 对象 进入 完成 状态 时会 触发 , 并 传递 结果 ;rejectedHandler 函数 会 在 拒绝 状态 下 调用 。Jquery 在 1.5 的 版本 中 引入 了 一个 新 的 概念 叫 Deferred, 就是 CommonJS promise A 标准 的 一种 衍生 。 可以 在 jQuery 中 创建 $.Deferref 的 对象 。 同时 也 对 发送 ajax 请求 以及 数据类型 有 了 新 的 修改 , 参考 JQuery API。 除了 以上 四种 ,javascript 中 还 可以 利用 各种 函数 模拟 异步 方式 , 更 有 诡异 的 诸如 用 同步 调用 异步 的 casejavascript 面向对象编程 《JavaScript 面向对象编程 指南 》 内容 包括 :JavaScript 作为 一门 浏览器 语言 的 核心思想 ; 面向对象编程 的 基础知识 及其 在 JavaScript 中 的 运用 ; 数据类型 、 操作符 以及 流程 控制 语句 ; 函数 、 闭 包 、 对象 和 原型 等 概念 , 以 代码 重用 为 目的 的 继承 模式 ;BOM、DOM、 浏览器 事件 、AJAX 和 JSON; 如何 实现 JavaScript 中 缺失 的 面向对象 特性 , 如 对象 的 私有 成员 与 私有 方法 ; 如何 应用 适当 的 编程 模式 , 发挥 JavaScript 语言 特有 的 优势 ; 如何 应用 设计模式 解决 常见问题 等 。《JavaScript 面向对象编程 指南 》 着重 介绍 JavaScript 在 面向对象 方面 的 特性 , 展示 如何 构建 强健 的 、 可 维护 的 、 功能强大 的 应用程序 及 程序库 。 编程 思想 函数 式 编程 > 维基 定义 函数 式 编程 ( 英语 :functional programming), 又称 泛 函 编程 , 是 一种 编程 范式 , 它 将 电脑 运算 视为 数学 上 的 函数 计算 , 并且 避免 使用 程序 状态 以及 易变 对象 。 函数 式 编程 的 历史 已经 很 悠久 了 , 但是 最近 几年 却 频繁 的 出现 在 大众 的 视野 , 很多 不 支持 函数 式 编程 的 语言 也 在 积极 加入 闭 包 , 匿名 函数 等 非常 典型 的 函数 式 编程 特性 。 大量 的 前端 框架 也 标榜 自己 使用 了 函数 式 编程 的 特性 , 好像 一旦 跟 函数 式 编程 沾边 , 就 很 高大 上 一样 , 而且 还有 一些 专门 针对 函数 式 编程 的 框架 和 库 , 比如 :RxJS、cycleJS、ramdaJS、lodashJS、underscoreJS 等 。 函数 式 编程 变得 越来越 流行 , 掌握 这种 编程 范式 对 书写 高质量 和 易于 维护 的 代码 都 大 有 好处 , 所以 我们 有 必要 掌握 它 。 参考 : 函数 式 编程 一 纯 函数 // 纯 函数 :Array.prototype.sliceArray.prototype.mapString.prototype.toUpperCase// 非 纯 函数 :Math.randomDate.nowArray.ptototype.splice 函数 柯 里 化 >curry 的 概念 很 简单 : 将 一个 低阶 函数 转换 为 高阶 函数 的 过程 就 叫 柯 里 化 。 这 表明 函数 柯 里 化 是 一种 “ 预 加载 ” 函数 的 能力 , 通过 传递 一 到 两个 参数 调用函数 , 就 能 得到 一个 记住 了 这些 参数 的 新 函数 。 从 某种意义 上 来讲 , 这 是 一种 对 参数 的 缓存 , 是 一种 非常 高效 的 编写 函数 的 方法 :// 纯 函数 checkAgevar checkAge = function(age) { var minimum = 21; return age >= minimum;};//curry checkAgevar checkage = min => (age => age > min);var checkage18 = checkage(18);checkage18(20);// =>true 函数 式 组合 var toUpperCase = function(x) { return x.toUpperCase(); };var exclaim = function(x) { return x + '!'; };var shout = function(x){ return exclaim(toUpperCase(x));};shout(\"send in the clowns\");//=> \"SEND IN THE CLOWNS!\" 使用 组合 , 我们 可以 这样 定义 我们 的 shout 函数 // 定义 composevar compose = (...args) => x => args.reduceRight((value, item) => item(value), x);var toUpperCase = function(x) { return x.toUpperCase(); };var exclaim = function(x) { return x + '!'; };var shout = compose(exclaim, toUpperCase);shout(\"send in the clowns\");//=> \"SEND IN THE CLOWNS!\" 声明 式 和 命令式 代码 > 命令式 代码 : 命令 “ 机器 ” 如何 去 做 事情 (how), 这样 不管 你 想要 的 是 什么 (what), 它 都 会 按照 你 的 命令 实现 。> 声明 式 代码 : 告诉 “ 机器 ” 你 想要 的 是 什么 (what), 让 机器 想 出 如何 去 做 (how)。// 命令式 var makes = [];for (var i = 0; i < cars.length; i++) { makes.push(cars[i].make);}// 声明 式 var makes = cars.map(function(car){ return car.make; });","title":" 编码 名词 整理 ","oriTitle":"编码名词整理"},{"uri":"/posts/summary-javascript-window-explain","tags":["Javascript"],"content":" [toc] 在 不同 的 DTD 下 , 获取 页面 属性 的 方法 是 不同 的 在 设计 页面 时 可能 经常 会 用到 固定 层 的 位置 , 这 就 需要 获取 一些 html 对象 的 坐标 以 更 灵活 的 设置 目标 层 的 坐标 , 这里 可能 就 会 用到 document .body.scrollTop 等 属性 , 但是 此 属性 在 xhtml 标准 网页 或者 更 简单 的 说 是 带 标签 的 页面 里 得到 的 结果 是 0, 如果 不要 此 标签 则 一切正常 , 那么 在 xhtml 页面 怎么 获得 body 的 坐标 呢 , 当然 有 办法 - 使用 document .documentElement 来 取代 document .body, 可以 这样 写 例 :var top = document .documentElement.scrollTop || document .body.scrollTop; 在 javascript 里 || 是 个 好 东西 , 除了 能 用 在 if 等 条件 判断 里 , 还 能 用 在 变量 赋值 上 。 那么 上 例 等同于 下 例 。 例 :var top = document .documentElement.scrollTop ? document .documentElement.scrollTop : document .body.scrollTop; 这么 写 可以 得到 很 好 的 兼容性 。 相反 , 如果 不做声 明 的话 ,document .documentElement.scrollTop 反而 会 显示 为 0。event 对象 的 clientX,offsetX,screenX,pageX 区别 >event.clientX、event.clientY 鼠标 相对 于 浏览器 窗口 可视 区域 的 X,Y 坐标 ( 窗口 坐标 ), 可视 区域 不 包括 工具栏 和 滚动条 。IE 事件 和 标准 事件 都 定义 了 这 2 个 属性 >event.pageX、event.pageY 类似 于 event.clientX、event.clientY, 但 它们 使用 的 是 文档 坐标 而 非 窗口 坐标 。 这 2 个 属性 不是 标准 属性 , 但 得到 了 广泛支持 。IE 事件 中 没有 这 2 个 属性 。>event.offsetX、event.offsetY 鼠标 相对 于 事件 源 元素 (srcElement) 的 X,Y 坐标 , 只有 IE 事件 有 这 2 个 属性 , 标准 事件 没有 对应 的 属性 。( 不 包含 border)>event.screenX、event.screenY 鼠标 相对 于 用户 显示器 屏幕 左上角 的 X,Y 坐标 。 标准 事件 和 IE 事件 都 定义 了 这 2 个 属性 >layerX/Y: 除 IE 外 与 pageX/Y 相同 ,IE11 下 与 clientX/Y 相同 。 非官方 属性 。 说明 : 都 包含 有 Height,Width,Top.Left 四个 属性 。(1)Height 和 Width 表示 元素 块 的 高度 和 宽度 。client: 包含 padding, 不 包含 border,margin 和 scrollbar 部分 offset: 包含 padding 和 border, 但是 不 包含 margin 和 scrollbar 部分 scroll: 包含 元素 的 所有 部分 。(2)Top 和 Left 是 用于 表示 元素 的 位置 。clientLeft: 通常 指 元素 的 左 边框 的 宽度 offsetLeft: 与 最近 的 父 元素 的 距离 ( 横向 )scroll: 卷 起来 的 距离 , 如果 没有 出现 scrollbar, 那么 这个 值 始终 为 0。(3) 各个 属性 一览 offsetTop 指 元素 距离 上方 或 上层 控件 的 位置 , 整型 , 单位 像素 。offsetLeft 指 元素 距离 左方 或 上层 控件 的 位置 , 整型 , 单位 像素 。offsetWidth 指 元素 控件 自身 的 宽度 , 整型 , 单位 像素 。offsetHeight 指 元素 控件 自身 的 高度 , 整型 , 单位 像素 。 网页 可见 区域 宽 :document.body.clientWidth 网页 可见 区域 高 :document.body.clientHeight 网页 可见 区域 宽 :document.body.offsetWidth ( 包括 border 边线 的 宽 ) 网页 可见 区域 高 :document.body.offsetHeight ( 包括 border 边线 的 宽 ) 网页 正文 全文 宽 :document.body.scrollWidth 网页 正文 全文 高 :document.body.scrollHeight 网页 被 卷 去 的 高 :document.body.scrollTop 网页 被 卷 去 的 左 :document.body.scrollLeft 网页 正文 部分 上 :window.screenTop 网页 正文 部分 左 :window.screenLeft 屏幕 分辨率 的 高 :window.screen.height 屏幕 分辨率 的 宽 :window.screen.width 屏幕 可用 工作 区 高度 :window.screen.availHeight 屏幕 可用 工作 区 宽度 :window.screen.availWidth 工作 区 高度 document.documentElement.clientHeight;scrollHeight: 获取 对象 的 滚动 高度 。scrollLeft: 设置 或 获取 位于 对象 左 边界 和 窗口 中 目前 可见 内容 的 最 左端 之间 的 距离 scrollTop: 设置 或 获取 位于 对象 最 顶端 和 窗口 中 可见 内容 的 最 顶端 之间 的 距离 scrollWidth: 获取 对象 的 滚动 宽度 offsetHeight: 获取 对象 相对 于 版面 或 由 父 坐标 offsetParent 属性 指定 的 父 坐标 的 高度 offsetLeft: 获取 对象 相对 于 版面 或 由 offsetParent 属性 指定 的 父 坐标 的 计算 左侧 位置 offsetTop: 获取 对象 相对 于 版面 或 由 offsetTop 属性 指定 的 父 坐标 的 计算 顶端 位置 event.clientX 相对 文档 的 水平 坐标 event.clientY 相对 文档 的 垂直 坐标 event.offsetX 相对 容器 的 水平 坐标 ( 设置 或 获取 鼠标 指针 位置 相对 于 触发 事件 的 对象 的 x 坐标 。)event.offsetY 相对 容器 的 垂直 坐标 document .documentElement.scrollTop 垂直 方向 滚动 的 值 event.clientX+document .documentElement.scrollTop 相对 文档 的 水平 座标 + 垂直 方向 滚动 的 量 Post by molong on 2009-05-19 11:57 PM #1 要 获取 当前 页面 的 滚动条 纵坐标 位置 , 用 :document .documentElement.scrollTop; 而 不是 :document .body.scrollTop;documentElement 对应 的 是 html 标签 , 而 body 对应 的 是 body 标签 。 在 标准 w3c 下 ,document .body.scrollTop 恒 为 0, 需要 用 document .documentElement.scrollTop 来 代替 ; 如果 你 想 定位 鼠标 相对 于 页面 的 绝对 位置 时 , 你 会 发现 google 里面 1000 篇文章 里面 有 999.99 篇 会 让 你 使用 event.clientX+document .body.scrollLeft,event.clientY+document .body.scrollTop, 如果 你 发现 你 的 鼠标 定位 偏离 了 你 的 想象 , 请 不要 奇怪 , 这 是 再 正常 不过 的 事情 。ie5.5 之后 已经 不 支持 document .body.scrollX 对象 了 。 所以 在 编程 的 时候 , 请 加上 这样 的 判断 if (document.body && document.body.scrollTop && document.body.scrollLeft){ top=document .body.scrollTop; left=document .body.scrollleft;}if (document.documentElement && document.documentElement.scrollTop && document.documentElement.scrollLeft){ top=document.documentElement.scrollTop; left=document.documentElement.scrollLeft; 先 总结 下 区别 :event.clientX、event.clientY 鼠标 相对 于 浏览器 窗口 可视 区域 的 X,Y 坐标 ( 窗口 坐标 ), 可视 区域 不 包括 工具栏 和 滚动条 。IE 事件 和 标准 事件 都 定义 了 这 2 个 属性 event.pageX、event.pageY 类似 于 event.clientX、event.clientY, 但 它们 使用 的 是 文档 坐标 而 非 窗口 坐标 。 这 2 个 属性 不是 标准 属性 , 但 得到 了 广泛支持 。IE 事件 中 没有 这 2 个 属性 。event.offsetX、event.offsetY 鼠标 相对 于 事件 源 元素 (srcElement) 的 X,Y 坐标 , 只有 IE 事件 有 这 2 个 属性 , 标准 事件 没有 对应 的 属性 。event.screenX、event.screenY 鼠标 相对 于 用户 显示器 屏幕 左上角 的 X,Y 坐标 。 标准 事件 和 IE 事件 都 定义 了 这 2 个 属性 这里 说 说 四种 浏览器 对 document.body 的 clientHeight、offsetHeight 和 scrollHeight 的 解释 。 这 四种 浏览器 分别 为 IE(Internet Explorer)、NS(Netscape)、Opera、FF(FireFox)。clientHeight 简介 四种 浏览器 对 clientHeight 的 解释 都 没有 什么 异议 , 都 认为 是 内容 可视 区域 的 高度 , 也就是说 页面 浏览器 中 可以 看到 内容 的 这个 区域 的 高度 , 一般 是 最后 一个 工具条 以下 到 状态栏 以上 的 这个 区域 , 与 页面 内容 无关 。offsetHeight 简介 IE、Opera 认为 offsetHeight = clientHeight + 滚动条 + 边框 。NS、FF 认为 offsetHeight 是 网页内容 实际 高度 , 可以 小于 clientHeight。scrollHeight 简介 IE、Opera 认为 scrollHeight 是 网页内容 实际 高度 , 可以 小于 clientHeight。NS、FF 认为 scrollHeight 是 网页内容 高度 , 不过 最小值 是 clientHeight 简单 地 说 clientHeight 就是 透过 浏览器 看 内容 的 这个 区域 高度 。NS、 FF 认为 offsetHeight 和 scrollHeight 都 是 网页内容 高度 , 只不过 当 网页内容 高度 小于 等于 clientHeight 时 ,scrollHeight 的 值 是 clientHeight, 而 offsetHeight 可以 小于 clientHeight。IE、Opera 认为 offsetHeight 是 可视 区域 clientHeight 滚动条 加 同理 clientWidth、offsetWidth 和 scrollWidth 的 解释 与 上面 相同 , 只是 把 高度 换成 宽度 即可 。 但是 FF 在 不同 的 DOCTYPE 中 对 clientHeight 的 解释 不同 , xhtml 1 trasitional 中 则 不是 如 上 解释 的 。 其它 浏览器 则 不 存在 此 问题 。[demo] scrollWidth ,clientWidth , offsetWidth 通过 一个 demo 测试 这 三个 属性 的 差别 。 说明 :scrollWidth: 对象 的 实际 内容 的 宽度 , 不 包 边线 宽度 , 会 随 对象 中 内容 超过 可视区 后 而 变 大 。clientWidth: 对象 内容 的 可视区 的 宽度 , 不 包 滚动条 等 边线 , 会 随 对象 显示 大小 的 变化 而 改变 。offsetWidth: 对象 整体 的 实际 宽度 , 包 滚动条 等 边线 , 会 随 对象 显示 大小 的 变化 而 改变 。 该 demo 就 在 页面 中 放 一个 textarea 元素 , 采用 默认 宽 高 显示 。 情况 1: 元素 内 无 内容 或者 内容 不 超过 可视区 , 滚动 不 出现 或 不可 用 的 情况 下 。scrollWidth=clientWidth, 两者 皆 为 内容 可视区 的 宽度 。offsetWidth 为 元素 的 实际 宽度 。 情况 2: 元素 的 内容 超过 可视区 , 滚动条 出现 和 可用 的 情况 下 。scrollWidth>clientWidth。scrollWidth 为 实际 内容 的 宽度 。clientWidth 是 内容 可视区 的 宽度 。offsetWidth 是 元素 的 实际 宽度 。 来源 : http://www.cnblogs.com/kongxianghai/p/4192032.html 介绍 :1、offsetLeft 假设 obj 为 某个 HTML 控件 。obj.offsetTop 指 obj 距离 上方 或 上层 控件 的 位置 , 整型 , 单位 像素 。obj.offsetLeft 指 obj 距离 左方 或 上层 控件 的 位置 , 整型 , 单位 像素 。obj.offsetWidth 指 obj 控件 自身 的 宽度 , 整型 , 单位 像素 。obj.offsetHeight 指 obj 控件 自身 的 高度 , 整型 , 单位 像素 。 我们 对 前面 提到 的 “ 上方 或 上层 ” 与 “ 左方 或 上层 ” 控件 作 个 说明 。 例如 :“ 提交 ” 按钮 的 offsetTop 指 “ 提交 ” 按钮 距 “tool” 层 上 边框 的 距离 , 因为 距 其 上边 最近 的 是 “tool” 层 的 上 边框 。“ 重置 ” 按钮 的 offsetTop 指 “ 重置 ” 按钮 距 “tool” 层 上 边框 的 距离 , 因为 距 其 上边 最近 的 是 “tool” 层 的 上 边框 。“ 提交 ” 按钮 的 offsetLeft 指 “ 提交 ” 按钮 距 “tool” 层 左 边框 的 距离 , 因为 距 其 左边 最近 的 是 “tool” 层 的 左 边框 。“ 重置 ” 按钮 的 offsetLeft 指 “ 重置 ” 按钮 距 “ 提交 ” 按钮 右边 框 的 距离 , 因为 距 其 左边 最近 的 是 “ 提交 ” 按钮 的 右边 框 。 以上 属性 在 FireFox 中 也 有效 。 另 外 : 我们 这里 所说 的 是 指 HTML 控件 的 属性 值 , 并 不是 document.body,document.body 的 值 在 不同 浏览器 中 有 不同 解释 ( 实际上 大多数 环境 是 由于 对 document.body 解释 不同 造成 的 , 并 不是 由于 对 offset 解释 不同 造成 的 ), 点击 这里 查看 不同点 。 标题 :offsetTop 与 style.top 的 区别 预备 知识 :offsetTop、offsetLeft、offsetWidth、offsetHeight 我们 知道 offsetTop 可以 获得 HTML 元素 距离 上方 或 外层 元素 的 位置 ,style.top 也 是 可以 的 , 二者 的 区别 是 : 一 、offsetTop 返回 的 是 数字 , 而 style.top 返回 的 是 字符串 , 除了 数字 外 还 带有 单位 :px。 二 、offsetTop 只读 , 而 style.top 可 读写 。 三 、 如果 没有 给 HTML 元素 指定 过 top 样式 , 则 style.top 返回 的 是 空 字符串 。offsetLeft 与 style.left、offsetWidth 与 style.width、offsetHeight 与 style.height 也 是 同样 道理 。 标题 :clientHeight、offsetHeight 和 scrollHeight 我们 这里 说 说 四种 浏览器 对 document.body 的 clientHeight、offsetHeight 和 scrollHeight 的 解释 , 这里 说 的 是 document.body, 如果 是 HTML 控件 , 则 又 有 不同 , 点击 这里 查看 。 这 四种 浏览器 分别 为 IE(Internet Explorer)、NS(Netscape)、Opera、FF(FireFox)。3、scrollLeftscrollTop 是 “ 卷 ” 起来 的 高度 值 , 示例 : 如果 为 p 设置 了 scrollTop, 这些 内容 可能 不会 完全 显示 。var p = document.getElementById(\"p\");p.scrollTop = 10; 由于 为 外层 元素 p 设置 了 scrollTop, 所以 内层 元素 会 向 上卷 。scrollLeft 也 是 类似 道理 。 我们 已经 知道 offsetHeight 是 自身 元素 的 宽度 。 而 scrollHeight 是 内部 元素 的 绝对 宽度 , 包含 内部 元素 的 隐藏 的 部分 。 上述 中 p 的 scrollHeight 为 300, 而 p 的 offsetHeight 为 100。scrollWidth 也 是 类似 道理 。IE 和 FireFox 全面 支持 , 而 Netscape 和 Opera 不 支持 scrollTop、scrollLeft(document.body 除外 )。 标题 :offsetTop、offsetLeft、offsetWidth、offsetHeight4、clientLeft 返回 对象 的 offsetLeft 属性 值 和 到 当前 窗口 左边 的 真实 值 之间 的 距离 , 可以 理解 为 边框 的 长度 一直 以来 对 offsetLeft,offsetTop,scrollLeft,scrollTop 这 几个 方法 很 迷糊 , 花 了 一天 的 时间 好好 的 学习 了 一下 . 得出 了 以下 的 结果 :1.offsetTop : 当前 对象 到 其 上级 层 顶部 的 距离 . 不能 对 其 进行 赋值 . 设置 对象 到 页面 顶部 的 距离 请 用 style.top 属性 . 获取 当前 元素 到 document 的 高度 , 建议 使用 jquery 的 offset().top2.offsetLeft : 当前 对象 到 其 上级 层 左边 的 距离 . 不能 对 其 进行 赋值 . 设置 对象 到 页面 左 部 的 距离 请 用 style.left 属性 .3.offsetWidth : 当前 对象 的 宽度 . 与 style.width 属性 的 区别 在于 : 如 对象 的 宽度 设定值 为 百分比 宽度 , 则 无论 页面 变 大 还是 变小 ,style.width 都 返回 此 百分比 , 而 offsetWidth 则 返回 在 不同 页面 中 对象 的 宽度 值 而 不是 百分比 值 4.offsetHeight : 与 style.height 属性 的 区别 在于 : 如 对象 的 宽度 设定值 为 百分比 高度 , 则 无论 页面 变 大 还是 变小 ,style.height 都 返回 此 百分比 , 而 offsetHeight 则 返回 在 不同 页面 中 对象 的 高度 值 而 不是 百分比 值 5.offsetParent : 当前 对象 的 上级 层 对象 . 注意 . 如果 对象 是 包括 在 一个 DIV 中 时 , 此 DIV 不会 被 当做 是 此 对象 的 上级 层 ,( 即 对象 的 上级 层 会 跳 过 DIV 对象 ) 上级 层 是 Table 时 则 不会 有 问题 . 利用 这个 属性 , 可以 得到 当前 对象 在 不同 大小 的 页面 中 的 绝对 位置 . 得到 绝对 位置 脚本 代码 function GetPosition(obj){var left = 0;var top = 0;while(obj != document.body){left = obj.offsetLeft;top = obj.offsetTop;obj = obj.offsetParent;}alert(\"Left Is : \" + left + \"\\r\\n\" + \"Top Is : \" + top);}6.scrollLeft : 对象 的 最 左边 到 对象 在 当前 窗口 显示 的 范围 内 的 左边 的 距离 . 即 是 在 出现 了 横向 滚动条 的 情况 下 , 滚动条 拉动 的 距离 .7.scrollTop 对象 的 最 顶部 到 对象 在 当前 窗口 显示 的 范围 内 的 顶 边 的 距离 . 即 是 在 出现 了 纵向 滚动条 的 情况 下 , 滚动条 拉动 的 距离 . 我们 这里 说 说 四种 浏览器 对 document.body 的 clientHeight、offsetHeight 和 scrollHeight 的 解释 , 这里 说 的 是 document.body, 如果 是 HTML 控件 , 则 又 有 不同 , 点击 这里 查看 。 这 四种 浏览器 分别 为 IE(Internet Explorer)、NS(Netscape)、Opera、FF(FireFox)。jQuery 中 offset(); position();> offset() : 获取 匹配 元素 在 当前 视 口 的 相对 偏移 。position(): 获取 匹配 元素 相对 父 元素 的 偏移 。","title":"javascript 【 窗口 】 的 offset、client、scroll 使用 方法 详解 ","oriTitle":"javascript 【窗口】的offset、client、scroll使用方法详解"},{"uri":"/posts/summary-js-mathfunction","tags":["Javascript"],"content":" 弧度 // 弧度 = π/180× 角度 // 角度 = 180/π× 弧度 var hd = Math.PI / 180 * 30 ; var jd = 180/Math.PI * hd; // 角度 = 180/Math.PI * Math.asin(1/2) console.log(Math.sin(Math.PI/180*30)); 圆周 长 圆周 长 = 直径 × Pi//jsMath.Pi()*2r//scssPi*2r","title":" 数学 函数 ","oriTitle":"数学函数"},{"uri":"/posts/summary-node-documents","tags":["node"],"content":"[toc] 前言 总结 了 8 点 : 使用 JavaScript 运行 于 服务端 的 平台 上 , 自然 继承 了 JavaScript 语言 的 一些 特性 ;Node.js 基于 单线程 、 基于 非 阻塞 I/O 模型 实现 ; 适合 于 数据 密集型 应用 , 不适 用于 计算 密集型 类 的 应用 ( 如 算法 等 ); 通过 使用 回调 函数 , 来 避免 同步 地 等待 I/O 操作 完成 ;Node.js 非核心 模块 非常 多 , 质量 可能 参差不齐 ( 使用 别人 贡献 的 模块 , 要 有 承担风险 的 准备 ); 因为 简单 , 开发 Node.js 应用程序 效率 很 高 ; 调试 相对 困难 , 调试 工具 可能 没有 其他 一些 比较 成熟 的 语言 ( 如 Java、C++ 等 ) 的 好 用 ;Node.js 基于 事件驱动 架构 ,events 模块 是 Node.js 最 核心 的 模块 。","title":"Node 开发 整理 ","oriTitle":"Node开发整理"},{"uri":"/posts/summary-node-express-params","tags":["node","express","Summary"],"content":"[toc]NODE 环境 设置 NODE_ENV=production 环境变量 怎么 设置 说明 通过 NODE_ENV 可以 来 设置 环境变量 ( 默认值 为 development)。 一般 我们 通过 检查 这个 值 来 分别 对 开发 环境 和 生产 环境 下 做 不同 的 处理 。 可以 在 命令行 中 通过 下面 的 方式 设置 这个 值 :linux & mac: export NODE_ENV=productionwindows:set NODE_ENV=production 比方说 如果 代码 中 要 对 生产 环境 下 做 一些 处理 , 可以 这样 写 :if (process.env.NODE_ENV === 'production') {// just for production code}//app.jsjsif ('dev' === app.get('env')) {app.use(morgan('dev'))// 中间件 日志 mongoose.set('debug', true);} 设置 环境变量 , 在 terminal 里面 运行 下面 的 命令 就 会 有 开发 环境 的 调试 数据 , 例如 日志 、mongodb 的 数据 操作 等等 。 一般 我们 通过 检查 这个 值 来 分别 对 开发 环境 和 生产 环境 下 做 不同 的 处理 。shellNODE_ENV=dev node app.jslinux 永久 设置 打开 配置文件 所在 所有 用户 都 生效 vim /etc/profile 当前 用户 生效 vim ~/.bash_profile 在 文件 末尾 添加 类似 如下 语句 进行 环境变量 的 设置 或 修改 在 文件 末尾 添加 如下 格式 的 环境变量 export path=$path:/home/download:/usr/local/export NODE_ENV = product 修改 /etc/profile 文件 后 source /etc/profile 修改 ~/.bash_profile 文件 后 source ~/.bash_profile* windows 下 *SET NODE_ENV=productionnode app.js// app.jsconsole.log(process.env.NODE_ENV);>To set an environment variable in Windows:SET NODE_ENV=development>on OS X or Linux:export NODE_ENV=developmentWe ran into this problem when working with node on Windows.Rather than requiring anyone who attempts to run the app to set these variables, we provided a fallback within the application.var environment = process.env.NODE_ENV || 'development';In a production environment, we would define it per the usual methods (SET/export).> tips//in package.json:\"scripts\": { \"start\": \"set NODE_ENV=dev && node app.js\"}//in app.js:console.log(process.env.NODE_ENV) // devconsole.log(process.env.NODE_ENV === 'dev') // falseconsole.log(process.env.NODE_ENV.length) // 4 (including a space at the end)//so, this may better:\"start\": \"set NODE_ENV=dev&& node app.js\"orconsole.log(process.env.NODE_ENV.trim() === 'dev') // true 如果 用 webstorm 开发 的话 QQ 截图 20160923115412.pngNode 版本 管理 windows: GNVMlinux: NVMosx : n 模块 用 Node.js 怎样 得到 json 的 长度 呢 ?var m ={\"a\":1,\"b\":2}Object.keys(a).lengthNodeJs: url.parse 方法 —— 将 一个 URL 字符串 转换成 对象 并 返回 。 方法 说明 : 讲 一个 URL 字符串 转换成 对象 并 返回 。 语法 : url.parse(urlStr, [parseQueryString], [slashesDenoteHost]) 接收 参数 :urlStr url 字符串 parseQueryString 为 true 时 将 使用 查询 模块 分析 查询 字符串 , 默认 为 falseslashesDenoteHost 默认 为 false,//foo/bar 形式 的 字符串 将 被 解释 成 { pathname: ‘//foo/bar' } 如果 设置 成 true,//foo/bar 形式 的 字符串 将 被 解释 成 { host: ‘foo', pathname: ‘/bar' }var url = require('url');var a = url.parse('http://example.com:8080/one?a=index&t=article&m=default');console.log(a);// 输出 结果 :{ protocol : 'http' , auth : null , host : 'example.com:8080' , port : '8080' , hostname : 'example.com' , hash : null , search : '?a=index&t=article&m=default', query : 'a=index&t=article&m=default', pathname : '/one', path : '/one?a=index&t=article&m=default', href : 'http://example.com:8080/one?a=index&t=article&m=default'}NodeJs:module.filename、filename、dirname、process.cwd() 和 require.main.filename 解惑 背景 一直 存在 一个 疑惑 ,require() 坐标 路径 是 啥 ?fs.readFile() 的 坐标 路径 又 是 啥 ? 总之 , 需要 路径 的 方法 , 我 总 有 这样 的 疑问 。 今天 就 实验 一下 , 给 弄清楚 。 实验 实验 素材 app.js1 // 执行 node E:\\nodestudy\\filepath_study\\app.js23 console.log('* app start *');4 5 console.log('* module.filename = ' + module.filename + ' *'); 6 console.log('* filename = ' + filename + ' *'); 7 console.log('* dirname = ' + dirname + ' *'); 8 console.log('* process.cwd() = ' + process.cwd() + ' *');9 console.log('* require.main.filename= ' + require.main.filename + ' *');1011 console.log('* app end *');1213 console.log('');1415 require('./lib/test');test.js1 console.log('* app start *');23 console.log('* module.filename = ' + module.filename + ' *');4 console.log('* filename = ' + filename + ' *');5 console.log('* dirname = ' + dirname + ' *');6 console.log('* process.cwd() = ' + process.cwd() + ' *');7 console.log('* require.main.filename= ' + require.main.filename + ' *');89 console.log('* app end *'); 结果 结论 module.filename: 开发 期间 , 该行 代码 所在 的 文件 。__filename: 始终 等于 module.filename。__dirname: 开发 期间 , 该行 代码 所在 的 目录 。process.cwd(): 运行 node 的 工作 目录 , 可以 使用 cd /d 修改 工作 目录 。require.main.filename: 用 node 命令 启动 的 module 的 filename, 如 node xxx, 这里 的 filename 就是 这个 xxx。require() 方法 的 坐标 路径 是 :module.filename;fs.readFile() 的 坐标 路径 是 :process.cwd()。Node 文件系统 上传 文件 原生 formidable ( 扩展 案例 见 Doracms)connect-formmultiple express4.x 最新 最 简单 的 方法 图片 压缩 var gm = requrie('gm') 错误 :this most likely means the gm/convert binaries can't be foundapt-get install imagemagick graphicsmagick 原因 :1、 没有 安装 GraphicsMagick2、 没有 配置 GraphicsMagick 的 path 环境变量 3、 安装 和 配置 path 环境变量 后 , 机器 没有 重新启动 。windows 下 安装 会 默认 配置 path 路径 :Node.js 的 process 模块 process 模块 用来 与 当前 进程 互动 , 可以 通过 全局变量 process 访问 , 不必 使用 require 命令 加载 。 它 是 一个 EventEmitter 对象 的 实例 。 属性 >process 对象 提供 一系列 属性 , 用于 返回 系统 信息 。process.pid: 当前 进程 的 进程 号 。process.version:Node 的 版本 , 比如 v0.10.18。process.platform: 当前 系统 平台 , 比如 Linux。process.title: 默认值 为 “node”, 可以 自定义 该 值 。process.argv: 当前 进程 的 命令行 参数 数组 。 这 是 一个 数组 , 数组 里 存放 着 启动 这个 node.js 进程 各个 参数 和 命令 代码 , 官方 代码 一目了然 。process.env: 指向 当前 shell 的 环境变量 , 比如 process.env.HOME。process.execPath: 运行 当前 进程 的 可执行文件 的 绝对路径 。 返回 当前 node.js 进程 的 启动 命令 路径 , 也 就是 node.js 安装 目录 下 的 node 命令 路径 , 是 一个 绝对路径 $ node test.js url: /usr/local/bin/node process.stdout: 指向 标准 输出 。process.stdin: 指向 标准 输入 。process.stderr: 指向 标准 错误 。 下面 是 主要 属性 的 介绍 。(1)stdoutprocess.stdout 用来 控制 标准 输出 , 也 就是 在 命令行 窗口 向 用户 显示 内容 。 它 的 write 方法 等同于 console.log。exports.log = function() { process.stdout.write(format.apply(this, arguments) + '\\n');};(2)argvprocess.argv 返回 命令行 脚本 的 各个 参数 组成 的 数组 。 先 新建 一个 脚本 文件 argv.js。// argv.jsconsole.log(\"argv: \",process.argv);console.log(\"argc: \",process.argc); 在 命令行 下 调用 这个 脚本 , 会 得到 以下 结果 。node argv.js a b c[ 'node', '/path/to/argv.js', 'a', 'b', 'c' ] 上面 代码 表示 ,argv 返回 数组 的 成员 依次 是 命令行 的 各个 部分 。 要 得到 真正 的 参数 部分 , 可以 把 argv.js 改写 成 下面 这样 。// argv.jsvar myArgs = process.argv.slice(2);console.log(myArgs); 方法 >process 对象 提供 以下 方法 :process.exit(): 退出 当前 进程 。process.cwd(): 返回 运行 当前 脚本 的 工作 目录 的 路径 。_process.chdir(): 改变 工作 目录 。process.nextTick(): 将 一个 回调 函数 放在 下次 事件 循环 的 顶部 。process.chdir() 改变 工作 目录 的 例子 。process.cwd()'/home/aaa'process.chdir('/home/bbb')process.cwd()'/home/bbb'process.nextTick() 的 例子 , 指定 下次 事件 循环 首先 运行 的 任务 。process.nextTick(function () { console.log('Next event loop!');}); 上面 代码 可以 用 setTimeout 改写 , 但是 nextTick 的 效果 更 高 、 描述 更 准确 。setTimeout(function () { console.log('Next event loop!');}, 0) 事件 (1)exit 事件 当前 进程 退出 时 , 会 触发 exit 事件 , 可以 对 该 事件 指定 回调 函数 。 这 一个 用来 定时 检查 模块 的 状态 的 好 钩子 (hook)( 例如 单元测试 ), 当 主 事件 循环 在 执行 完 ’exit’ 的 回调 函数 后 将 不再 执行 , 所以 在 exit 事件 中 定义 的 定时器 可能 不会 被 加入 事件 列表 .process.on('exit', function () { fs.writeFileSync('/tmp/myfile', 'This MUST be saved on exit.');});(2)uncaughtException 事件 当前 进程 抛出 一个 没有 被 捕捉 的 意外 时 , 会 触发 uncaughtException 事件 。process.on('uncaughtException', function (err) { console.error('An uncaught error occurred!'); console.error(err.stack);});npmnpm package.json 中 的 dependencies 和 devDependencies 的 区别 一个 node package 有 两种 依赖 , 一种 是 dependencies 一种 是 devDependencies, 其中 前者 依赖 的 项 该是 正常 运行 该 包 时 所 需要 的 依赖 项 , 而 后者 则 是 开发 的 时候 需要 的 依赖 项 , 像 一些 进行 单元测试 之类 的 包 。 如果 你 将 包 下载 下来 在 包 的 根目录 里 运行 npm install 默认 会 安装 两种 依赖 , 如果 你 只是 单纯 的 使用 这个 包 而 不 需要 进行 一些 改动 测试 之类 的 , 可以 使用 npm install --production 只 安装 dependencies 而 不 安装 devDependencies。 如果 你 是 通过 以下 命令 进行 安装 npm install packagename 那么 只 会 安装 dependencies, 如果 想要 安装 devDependencies, 需要 输入 npm install packagename --devNodejs expressNodejs express 获取 url 参数 ,post 参数 的 三种 方式 :express 获取 参数 有 三种 方法 : 官 网 实例 :Checks route params (req.params), ex: /user/:idChecks query string params (req.query), ex: ?id=12Checks urlencoded body params (req.body), ex: 表单 值 或 post 的 值 Node 原生 方法 url.parse(urlString[, parseQueryString[, slashesDenoteHost]])// 示例 :(req.){ params = url.(req.)searchKey = params..area = req..}1、 例如 :127.0.0.1:3000/index, 这种 情况 下 , 我们 为了 得到 index, 我们 可以 通过 使用 req.params 得到 , 通过 这种 方法 我们 就 可以 很 好 的 处理 Node 中 的 路由 处理 问题 , 同时 利用 这点 可以 非常 方便 的 实现 MVC 模式 ;2、 例如 :127.0.0.1:3000/index?id=12, 这种 情况 下 , 这种 方式 是 获取 客户端 get 方式 传递 过来 的 值 , 通过 使用 req.query.id 就 可以 获得 , 类似 于 PHP 的 get 方法 ;3、 例如 :127.0.0.1:300/index, 然后 post 了 一个 id=2 的 值 , 这种 方式 是 获取 客户端 post 过来 的 数据 , 可以 通过 req.body.id 获取 , 类似 于 PHP 的 post 方法 ; 注 :post 请求 需要 导入 body-parservar express = require(\"express\");var bodyParser = require(\"body-parser\");var app = express();// need it...app.use(bodyParser.urlencoded({ extended: false }));app.post('/login',function(req,res){ var user_name=req.body.user; var password=req.body.password; console.log(\"User name = \"+user_name+\", password is \"+password); res.end(\"yes\");});// 3-1 表单 post 传递 参数 至 后台 : 提交 添加 //app.jsvar express = require('express');var router = express.Router();router.route('/add').post(function(req, res) { var userObj = {}; userObj = { name: req.body.name, age: req.body.age, job: req.body.job, hobby: req.body.hobby }; console.log(userObj); // {name:'xq',age:'12',job:'coder',hobby:'run'}});}//3-2 jquery ajax 传递 参数 至 后台 :var _id = '123456';$.post('/user/delete', { id: _id }, function(data) { if (data.error) { $('#removeTips').html(' 删除异常 :' + data.error + ' 请 刷新 重试 。'); }else { window.location.href = '/admin/'; }}, 'json');//app.jsvar express = require('express');var router = express.Router();router.route('/user/delete').post(function(req, res) { var _id = req.body.id; console.log(_id); // 123456});}//2-1 req.query 该 属性 只能 获取 “express 路由器 传递 的 参数 ”, 值得一提的是 : 与 req.params 配合 还 能 在 express 路由器 中 玩 正则 。GET /search?q=tobi+ferret req.query.q=> \"tobi ferret\"GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse req.query.order=> \"desc\"req.query.shoe.color 数据 传递 :1. 中间件 :body-Parser: ( 配置 ) 取 body 中 数据 var bodyParser = require('body-parser');app.use(bodyParser.json());app.use(bodyParser.urlencoded({ extended: false })); 方法 :req.body.title,( 可取 , 或 title = $(\"input[name=\"title\"]\").val())2.params 获取 GET 方法 的 params 参数 req.params.3.url.parse 将 一个 URL 字符串 转换成 对象 并 返回 。 语法 : url.parse(urlStr, [parseQueryString], [slashesDenoteHost]) 接收 参数 :urlStr url 字符串 parseQueryString 为 true 时 将 使用 查询 模块 分析 查询 字符串 , 默认 为 falseslashesDenoteHost 默认 为 false,//foo/bar 形式 的 字符串 将 被 解释 成 { pathname: ‘//foo/bar' } 如果 设置 成 true,//foo/bar 形式 的 字符串 将 被 解释 成 { host: ‘foo', pathname: ‘/bar' } 例子 :var url = require('url');var a = url.parse('http://example.com:8080/one?a=index&t=article&m=default');console.log(a);// 输出 结果 :{ protocol : 'http' , auth : null , host : 'example.com:8080' , port : '8080' , hostname : 'example.com' , hash : null , search : '?a=index&t=article&m=default', query : 'a=index&t=article&m=default', pathname : '/one', path : '/one?a=index&t=article&m=default', href : 'http://example.com:8080/one?a=index&t=article&m=default'}node 模版 引擎 ejs ( 已 移除 layout)jade ( 逻辑性 好 , 缩进 问题 , 维护 难 )swig ( 观望 学习 )","title":"Node-express 数据 传递 【 个人 整理 】","oriTitle":"Node-express 数据传递【个人整理】"},{"uri":"/posts/summary-regexp-learn","tags":["regexp","Summary"],"content":"[toc]【1】 部分 语法 - 【 语法 】 构造函数 RegExp 对象 new RegExp('ab+c', 'i');new RegExp(/ab+c/, 'i'); 直接 量 语法 var re = /**/gi> 构造函数 正则 可 直接 使用 变量 正则表达式 的 () [] {} 有 不同 的 意思 。() 是 为了 提取 匹配 的 字符串 。 表达式 中 有 几个 () 就 有 几个 相应 的 匹配 字符串 。(\\s*) 表示 连续 空格 的 字符串 。[] 是 定义 匹配 的 字符 范围 。 比如 [a-zA-Z0-9] 表示 相应 位置 的 字符 要 匹配 英文 字符 和 数字 。[\\s] 表示 空格 或者 号 。{} 一般 用来 表示 匹配 的 长度 , 比如 \\s{3} 表示 匹配 三个 空格 ,\\s[1,3] 表示 匹配 一 到 三个 空格 。(0-9) 匹配 '0-9′ 本身 。 [0-9]* 匹配 数字 ( 注意 后面 有 *, 可以 为 空 )[0-9]+ 匹配 数字 ( 注意 后面 有 +, 不 可以 为 空 ){1-9} 写法 错误 。[0-9]{0,9} 表示 长度 为 0 到 9 的 数字 字符串 。// 构造函数 正则 需要 转义 --( 匹配 元字符 , 单词 边界 )\"never\".match(new RegExp(\"ver\\\\b\",'i'))\"never\".match(/ver\\b/,'i') 正则表达式 全部 符号 解释 table th:first-child { width: 100px;}| 字符 | 描述 || ------------- |:-------------|| 字符 符号 对照 说明 111111111111111 11111| 描述 |\\ | 将 下 一个 字符 标记 为 一个 特殊字符 、 或 一个 原义 字符 、 或 一个 向 后 引用 、 或 一个 八进制 转义 符 。 例如 ,'n' 匹配 字符 \"n\"。'\\n' 匹配 一个 换行符 。 序列 '\\\\' 匹配 \"\\\" 而 \"\\(\" 则 匹配 \"(\"。|^\t | 匹配 输入 字符串 的 开始 位置 。 如果 设置 了 RegExp 对象 的 Multiline 属性 ,^ 也 匹配 '\\n' 或 '\\r' 之后 的 位置 。|$\t | 匹配 输入 字符串 的 结束 位置 。 如果 设置 了 RegExp 对象 的 Multiline 属性 ,$ 也 匹配 '\\n' 或 '\\r' 之前 的 位置 。|*\t | 匹配 前面 的 子 表达式 零次 或 多次 。 例如 ,zo* 能 匹配 \"z\" 以及 \"zoo\"。* 等价 于 {0,}。|+\t | 匹配 前面 的 子 表达式 一次 或 多次 。 例如 ,'zo+' 能 匹配 \"zo\" 以及 \"zoo\", 但 不能 匹配 \"z\"。+ 等价 于 {1,}。|?\t | 匹配 前面 的 子 表达式 零次 或 一次 。 例如 ,\"do(es)?\" 可以 匹配 \"do\" 或 \"does\" 中 的 \"do\" 。? 等价 于 {0,1}。|{n} |\tn 是 一个 非 负 整数 。 匹配 确定 的 n 次 。 例如 ,'o{2}' 不能 匹配 \"Bob\" 中 的 'o', 但是 能 匹配 \"food\" 中 的 两个 o。|{n,} |\tn 是 一个 非 负 整数 。 至少 匹配 n 次 。 例如 ,'o{2,}' 不能 匹配 \"Bob\" 中 的 'o', 但 能 匹配 \"foooood\" 中 的 所有 o。'o{1,}' 等价 于 'o+'。'o{0,}' 则 等价 于 'o*'。|{n,m}|\tm 和 n 均 为 非 负 整数 , 其中 n RegExp.$1 是 RegExp 的 一个 属性 , 指 的 是 与 正则表达式 匹配 的 第一个 子 匹配 ( 以 括号 为 标志 ) 字符串 , 以此类推 ,RegExp.$2,RegExp.$3,..RegExp.$99 总共 可以 有 99 个 匹配 示例 应用 : 匹配 url 变量 //RegExp(\"({[A-Za-z]+[A-Za-z0-9]*})\",\"g\")var url = \"op/orderDetail.html?orderId={orderId}&flag=update\";url.replace(RegExp(\"({[A-Za-z]+[A-Za-z0-9]*})\",\"g\"),function($1){ console.log($1) //{orderId}\t//var $input = $parent.find(\"#\"+$1.replace(/[{}]+/g, \"\"));\t//return $input.val() ? $input.val() : $1;}) 需求 :table 列表 选中 获取 id, 填入 到 动态 链接 中 ; target 指向 更改 的 属性 ,rel 未 值 ,table 数据 获取 时会 自动 生成 target 对应 的 input[name=orderId] 选中 tr 会 更改 input[name=orderId], 点击 选项 li 会 {orderId} 会 替换 为 相应 的 值 。//js 生成 table \t \tvar trHtml=\"\"; \t \tif(0==((i + 1) % 2) ){ \t \t\ttrHtml=\"\"; \t \t}//html 选项 修改 // 触发 选项 $(\"a[target=navTab]\", $p).each(function() { $(this).click(function(event) { var url = unescape($this.attr(\"href\")).replaceTmById($(event.target).parents(\".unitBox:first\")); DWZ.debug('[target=navTab]: ' + url); ... ... navTab.openTab(tabid, url, { title: title, fresh: fresh, external: external }); event.preventDefault(); }); });\t\tfunction replaceTmById(_box){\t\t\tvar $parent = _box || $(document);\t\t\treturn this.replace(RegExp(\"({[A-Za-z]+[A-Za-z0-9]*})\",\"g\"), function($1){\t\t\t\tvar $input = $parent.find(\"#\"+$1.replace(/[{}]+/g, \"\"));\t\t\t\treturn $input.val() ? $input.val() : $1;\t\t\t});\t\t} 获取 URLfunction GetQueryString(name) { var reg = new RegExp(\"(^|&)\" + name + \"=(*)(&|$)\",\"i\"); var r = window.location.search.substr(1).match(reg); if (r!=null) return unescape(r[2]); return null; } 这个 正则 是 寻找 &+url 参数 名字 = 值 +&[object Object]& 可以 不 存在 。 例如 :RegExp(\"(^|&)logo_url=(*)(&|$)\") 匹配 这样 的 字符串 logo_url= 不是 & 的 任意 字符 &logo_url= 不是 & 的 任意 字符 &logo_url= 不是 & 的 任意 字符 &&logo_url= 不是 & 的 任意 字符 (*) 非 & 零个 或 多个 // 例 2 支持 ?saleid=111&mm=22?elid=aaavar reg = new RegExp(\"(^|&)\" + name + \"=(*)(&|$)\",\"i\"); 其实 就是 匹配 URL 中 logo_url 这个 参数 邮箱 匹配 虽然 没有 统一 的 邮箱 账号 格式 , 但是 所有 邮箱 都 符合 “ 名称 @ 域名 ” 的 规律 。 对于 名称 和 域名 的 字符 限制 , 我们 可以 根据 项目 的 情况 定义 一个 , 比如 只 允许 有 英文 、 数字 、 下划线 等 组成 。 下面 举例 实现 一些 验证 邮箱 格式 的 正则表达式 。 实例 1、 只 允许 英文字母 、 数字 、 下划线 、 英文 句号 、 以及 中 划线 组成 举例 :[email protected] 分析 邮件 名称 部分 :26 个 大小写 英文字母 表示 为 a-zA-Z 数字 表示 为 0-9 下划线 表示 为 _ 中 划线 表示 为 - 由于 名称 是 由 若干个 字母 、 数字 、 下划线 和 中 划线 组成 , 所以 需要 用到 + 表示 多次 出现 根据 以上 条件 得出 邮件 名称 表达式 :[a-zA-Z0-9_-]+ 分析 域名 部分 : 一般 域名 的 规律 为 “N 级 域名 二级域名 . 顶级 域名 ”, 比如 “qq.com”、“www.qq.com”、“mp.weixin.qq.com”、“12-34.com.cn”, 分析 可 得 域名 类似 “* .* .* .*” 组成 。“**” 部分 可以 表示 为 [a-zA-Z0-9_-]+“.**” 部分 可以 表示 为 \\.[a-zA-Z0-9_-]+ 多个 “.**” 可以 表示 为 (\\.[a-zA-Z0-9_-]+)+ 综上所述 , 域名 部分 可以 表示 为 [a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)+ 最终 表达式 : 由于 邮箱 的 基本 格式 为 “ 名称 @ 域名 ”, 需要 使用 “^” 匹配 邮箱 的 开始 部分 , 用 “$” 匹配 邮箱 结束 部分 以 保证 邮箱 前后 不能 有 其他 字符 , 所以 最终 邮箱 的 正则表达式 为 :^[a-zA-Z0-9-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9_-]+)+$ 实例 2、 名称 允许 汉字 、 字母 、 数字 , 域名 只 允许 英文 域名 举例 : 杨元庆 [email protected] 分析 邮件 名称 部分 : 汉字 在 正则 表示 为 [\\u4e00-\\u9fa5] 字母 和 数字 表示 为 A-Za-z0-9 通过 分析 得出 邮件 名称 部分 表达式 为 [A-Za-z0-9\\u4e00-\\u9fa5]+ 分析 邮件 域名 部分 邮件 部分 可以 参考 实例 1 中 的 分析 域名 部分 。 得出 域名 部分 的 表达式 为 [a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)+。 最终 表达式 : 我们 用 @ 符号 将 邮箱 的 名称 和 域名 拼接 起来 , 因此 完整 的 邮箱 表达式 为 ^[A-Za-z0-9\\u4e00-\\u9fa5]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)+$ 手机号码 if(!/^(((13[0-9]{1})|15[0-9]|17[0-9]|18[0-9])+\\d{8})$/.test(tel)){ $(\".form-box input[name='tel']\").after(errorTip.format(\" 手机号码 格式 不 对 \")) return}else{ window.location.href=\"bindSuccess.html\" } 隐藏 手机号码 , 手机号码 中间 部分 替换成 星号 // 匹配 手机号 首尾 , 以 类似 “123**8901” 的 形式 输出 '12345678901'.replace(/(\\d{3})\\d{4}(\\d{4})/, '$1**$2');// 匹配 连续 11 位 数字 , 并 替换 其中 的 前 7 位 为 * 号 '15110280327'.replace(/\\d{7}(\\d{4})/, '*$1'); 方法 ① : 字符串 截取 + 拼接 function formatPhone(phone) { if (typeof phone == 'number') { phone = phone.toString(); } return phone.substr(0, 3) + '**' + phone.substr(7, 11); } 正则表达式 替换 function formatPhone(phone) { return phone.replace(/(\\d{3})\\d{4}(\\d{4})/, \"$1**$2\");} 原理 是 先 匹配 前 3 个 数字 , 将 匹配 到 的 值 给 $1, 然后 匹配 中间 4 个 数字 , 再 匹配 最后 4 个 数字 给 $2。 小结 : 中间 4 位 替换成 * 号 , 为什么 不是 其他 位置 呢 , 首先 你 要 知道 手机号 的 规则 , 我国 使用 的 手机号码 是 11 位 的 , 前 3 位 是 号码 段 , 中间 4 位 是 地区 编码 , 最后 4 位 是 用户 编码 。 你 要 替换 多少 位 都 没关系 , 至少 让 人 知道 这 是 个 手机号码 就 可以 了 , 不过 替换 中间 4 位 , 是 约定俗成 的 哦 。 判断 图片 isImage: function (str) { return isString(str) && str.match(/(^data:image\\/.,)|(\\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\\?|#).)?$)/i);},isSWF: function (str) { return isString(str) && str.match(/\\.(swf)((\\?|#).*)?$/i); // 匹配 ? 或者 \"#\" 结尾 的 的 行 。},JS 利用 正则 配合 replace 替换 指定 字符 replace() 方法 用于 在 字符串 中 用 一些 字符 替换 另 一些 字符 , 或 替换 一个 与 正则表达式 匹配 的 子串 。 语法 stringObject.replace(regexp,replacement) 参数 描述 regexp 必需 。 规定 了 要 替换 的 模式 的 RegExp 对象 。 请 注意 , 如果 该 值 是 一个 字符串 , 则 将 它 作为 要 检索 的 直接 量 文本 模式 , 而 不是 首先 被 转换 为 RegExp 对象 。replacement 必需 。 一个 字符串 值 。 规定 了 替换 文本 或 生成 替换 文本 的 函数 。var s = \"123abc456xayz890\";var re = /(abc|xyz)/gi;console.log( s.replace(re,'') ) 返回值 一个 新 的 字符串 , 是 用 replacement 替换 了 regexp 的 第一次 匹配 或 所有 匹配 之后 得到 的 。 说明 字符串 stringObject 的 replace() 方法 执行 的 是 查找 并 替换 的 操作 。 它 将 在 stringObject 中 查找 与 regexp 相匹配 的 子 字符串 , 然后 用 replacement 来 替换 这些 子串 。 如果 regexp 具有 全局 标志 g, 那么 replace() 方法 将 替换 所有 匹配 的 子串 。 否则 , 它 只 替换 第一个 匹配 子串 。replacement 可以 是 字符串 , 也 可以 是 函数 。 如果 它 是 字符串 , 那么 没有 匹配 都 将 由 字符串 替换 。 但是 replacement 中 的 $ 字符 具有 特定 的 含义 。 如下 表 所示 , 它 说明 从 模式匹配 得到 的 字符串 将 用于 替换 。 字符 替换 文本 $1、$2、...、$99 与 regexp 中 的 第 1 到 第 99 个子 表达式 相匹配 的 文本 。 正则 对象 属性 按 序列 取出 var data = { \"222\": \"1111\", \"555\": \"4444\", \"1010\": \"9999\", \"8\": \"bbb\", \"111\": \"asdfj\",}Object.keys(JSON.parse(JSON.stringify(data).replace(/+(?=\":)/g,\"0$&\")))Object.keys(JSON.parse('{\"343\":33,\"133\":322,\"233\":43}'.replace(/+(?=\":)/g,\"0$&\")))//[\"0343\", \"0133\", \"0233\"] 正则 匹配 金额 ( 限制 一个 小数点 , 两个 小数 )// 要求 为 空 (\"\") 或 1 到 16 位 的 纯 数字 (0123456789)^(|[0-9]{1,16})$// 金额 , 限制 一个 小数点 , 两个 小数 // 给 输入 的 密码 框 添加 新 值 function addValue(newValue) { var reg = /^(\\d*((\\.)?(\\d{0,1})?))?$/; if(reg.test($(\".input_cur\").val())){ if($(\".shuru\").val().indexOf(\".\")>=1 && newValue==\".\"){ newValue = \"\"; } CapsLockValue == 0 ? $(\".inputcur\").val($(\".shuru\").val() + newValue) : $(\".inputcur\").val($(\".shuru\").val() + newValue.toUpperCase()) }}JavaScript 采用 正则表达式 实现 startWith、endWith 效果 函数 String.prototype.startWith=function(str){ var reg=new RegExp(\"^\"+str); return reg.test(this);}String.prototype.endWith=function(str){ var reg=new RegExp(str+\"$\"); return reg.test(this);}//indexOf() 实现 var index = str.indexOf('abc');if(index==0){// 以 'abc' 开头 } 匹配 小数点 , 金额 字体 区分 new RegExp(/(([1-9]\\d))(\\.\\d[0-9])/)//html59.60 元 / 台 //jswindow.onload = function(){ var company = document.querySelector(\".present-price sub\").innerHTML; var $parsePrice = document.querySelector(\".present-price span\"); var oldParse = parseFloat($parsePrice.innerHTML).toFixed(2); var reg = new RegExp(/(([1-9]\\d))(\\.\\d[0-9])/) if(reg.test(oldParse)){ var circle = \".\"+(oldParse.split(\".\"))[1] + company; $parsePrice.innerHTML = (oldParse.split(\".\")[0]); document.querySelector(\".present-price sub\").innerHTML = circle; }else{ $parsePrice.innerHTML = (oldParse.split(\".\")[0]); document.querySelector.innerHTML = \".00\" +company; }}indexOf 匹配 1234567.4567801233.1415926 var tags = document.getElementsByTagName('p'); for(var i = 0, len = tags.length; i ' + num + ''; } else { var integral = num.substring(0, num.indexOf('.')); var decimal = num.substring(num.indexOf('.')); tags[i].innerHTML = '' + integral + '' + decimal + ''; } } 浏览器 内核 版本 判断 // 判断 IE 版本 var browser = navigator.appNamevar b_version = navigator.appVersionvar version = b_version.split(\";\");var trim_Version = version[1].replace(/[ ]/g, \"\");if (browser == \"Microsoft Internet Explorer\" && trim_Version == \"MSIE6.0\") { alert(\"IE 6.0\");} else if (browser == \"Microsoft Internet Explorer\" && trim_Version == \"MSIE7.0\") { alert(\"IE 7.0\"); window.location.href = \"http://xxxx.com\";} else if (browser == \"Microsoft Internet Explorer\" && trim_Version == \"MSIE8.0\") { alert(\"IE 8.0\");} else if (browser == \"Microsoft Internet Explorer\" && trim_Version == \"MSIE9.0\") { alert(\"IE 9.0\");} 客户端 手机 端 判断 var os = function () { var ua = navigator.userAgent, isWindowsPhone = /(?:Windows Phone)/.test(ua), isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone, isAndroid = /(?:Android)/.test(ua), isFireFox = /(?:Firefox)/.test(ua), isChrome = /(?:Chrome|CriOS)/.test(ua), isTablet = /(?:iPad|PlayBook)/.test(ua) || (isAndroid && !/(?:Mobile)/.test(ua)) || (isFireFox && /(?:Tablet)/.test(ua)), isPhone = /(?:iPhone)/.test(ua) && !isTablet, isPc = !isPhone && !isAndroid && !isSymbian; return { isTablet: isTablet, isPhone: isPhone, isAndroid: isAndroid, isPc: isPc }; }();// 测试 if(os.isAndroid || os.isIphone) 微 信 浏览器 判断 判断 是否是 微 信 内置 浏览器 如果 用 微 信 浏览器 打开 可以 看到 下面 的 文字 window.onload = function(){if(isWeiXin()){var p = document.getElementsByTagName('p');p[0].innerHTML = window.navigator.userAgent;}}function isWeiXin(){var ua = window.navigator.userAgent.toLowerCase();if(ua.match(/MicroMessenger/i) == 'micromessenger'){return true;}else{return false;}}JS 数字 , 金额 用 逗号 隔开 ( 数字 格式化 ) 例如 :12345 格式化 为 12,345.0012345.6 格式化 为 12,345.6012345.67 格式化 为 12,345.67 只 留 两位 小数 。 回来 后写 了 个 格式化 函数 。 可以 控制 小数位 数 , 自动 四舍五入 。 代码 如下 :function fmoney(s, n) { n = n > 0 && nfunction fmoney(s, n) { n = n > 0 && n 小数点 位数 :2345 + 附 :/*formatMoney(s,type) 功能 : 金额 按 千位 逗号 分割 参数 :s, 需要 格式化 的 金额 数值 . 参数 :type, 判断 格式化 后 的 金额 是否 需要 小数位 . 返回 : 返回 格式化 后 的 数值 字符串 . */function formatMoney(s, type) { if (//.test(s)) return \"0\"; if (s == null || s == \"\") return \"0\"; s = s.toString().replace(/^(\\d*)$/, \"$1.\"); s = (s + \"00\").replace(/(\\d\\.\\d\\d)\\d/, \"$1\"); s = s.replace(\".\", \",\"); var re = /(\\d)(\\d{3},)/; while (re.test(s)) s = s.replace(re, \"$1,$2\"); s = s.replace(/,(\\d\\d)$/, \".$1\"); if (type == 0) {// 不 带 小数位 ( 默认 是 有 小数位 ) var a = s.split(\".\"); if (a[1] == \"00\") { s = a[0]; } } return s;}/* 通用 DateAdd(interval,number,date) 功能 : 实现 javascript 的 日期 相加 功能 . 参数 :interval, 字符串 表达式 , 表示 要 添加 的 时间 间隔 . 参数 :number, 数值 表达式 , 表示 要 添加 的 时间 间隔 的 个数 . 参数 :date, 时间 对象 . 返回 : 新 的 时间 对象 . var now = new Date(); var newDate = DateAdd(\"day\",5,now);author:devinhua( 从 ○ 开始 ) update:2010-5-5 20:35 */function DateAdd(interval, number, date) { if (date == null) return \"\"; switch (interval) { case \"day\": date = new Date(date); date = date.valueOf(); date += number * 24 * 60 * 60 * 1000; date = new Date(date); return date; break; default: return \"\"; break; }} 匹配 图片 文件 /\\.(jpg|jpeg|gif|png|bmp|GIF|JPG|PNG|BMP)$/.test(src)let files = e.target.files || e.dataTransfer.files;/^image/.test(file.type)","title":"【 正则 - 个人 整理 】","oriTitle":"【正则-个人整理】"},{"uri":"/posts/summary-vscode-webstorm-sublime-eclipe_setting","tags":["vscode","webstorm"],"content":"[toc]vscode> 格式化 1.vue 格式化 ——vetur2.js 格式化 prettier3.eslint 格式化 ( 完全 格式化 )//package.json \"eslint\": \"^4.19.1\", \"eslint-config-standard\": \"^11.0.0\", \"eslint-friendly-formatter\": \"^4.0.1\", \"eslint-loader\": \"^2.0.0\", \"eslint-plugin-import\": \"^2.11.0\", \"eslint-plugin-node\": \"^6.0.1\", \"eslint-plugin-promise\": \"^3.7.0\", \"eslint-plugin-standard\": \"^3.0.1\", \"eslint-plugin-vue\": \"^4.5.0\",// 配置 \"eslint.autoFixOnSave\": true, \"eslint.validate\": [ \"javascript\",{ \"language\": \"vue\", \"autoFix\": true }, \"html\", \"vue\" ],4. 配置 jsconfig.json import 路径 格式化 , 支持 alias 自定义 查找 { \"compilerOptions\":{ \"baseUrl\": \".\", \"paths\":{ \"@/\":[\"./src/\"] } }, \"include\": [\"./src/*/\"], \"exclude\": [\"node_modules\", \"dist\"]}5.LF,CRLF 切换 问题 //root = true[*]charset = utf-8indent_style = spaceindent_size = 2endofline = lfinsertfinalnewline = truetrimtrailingwhitespace = trueSublime 快捷键 // 定位 通用 Home 首 ,End 尾 PgUp PgDn 上下 // 当 页 定义 查看 ctrl + r// 区域 选择 (Expand Region)ctrl + shift + spaceEclipse//open resource (Navigation-resource ) 快速 查找 Ctrl+shift +RwebStorm// 选中 多 行列 位置 ALT+ 拖拽 查找 / 代替 ctrl+shift+N 通过 文件名 快速 查找 工程 内 的 文件 ( 必 记 )ctrl+shift+alt+N 通过 一个 字符 快速 查找 位置 ( 必 记 )ctrl+F 在 文件 内 快速 查找 代码 F3 查找 下 一个 shift+F3 查找 上 一个 ctrl+R 文件 内 代码 替换 ctrl+shift+R 指定 目录 内 代码 批量 替换 ctrl+shift+F 指定 目录 内 代码 批量 查找 ctrl+R 文件 内 代码 替换 界面 操作 ctrl+shift+A 快速 查找 并 使用 编辑器 所有 功能 ( 必 记 )alt+[0-9] 快速 拆 合 功能 界面 模块 ctrl+shift+F12 最大 区域 显示 代码 ( 会 隐藏 其他 的 功能 界面 模块 )alt+shift+F 将 当前 文件 加入 收藏夹 ctrl+alt+s 打开 配置 窗口 ctrl+tab 切换 代码 选项卡 ( 还要 进行 此 选择 , 效率 差些 )alt+ 切换 代码 选项卡 ctrl+shift+N 通过 文件名 快速 查找 工程 内 的 文件 ( 必 记 )ctrl+shift+alt+N 通过 一个 字符 快速 查找 位置 ( 必 记 )ctrl+F 在 文件 内 快速 查找 代码 F3 查找 下 一个 shift+F3 查找 上 一个 ctrl+R 文件 内 代码 替换 ctrl+shift+R 指定 目录 内 代码 批量 替换 ctrl+shift+F 指定 目录 内 代码 批量 查找 ctrl+R 文件 内 代码 替换 界面 操作 ctrl+shift+A 快速 查找 并 使用 编辑器 所有 功能 ( 必 记 )alt+[0-9] 快速 拆 合 功能 界面 模块 ctrl+shift+F12 最大 区域 显示 代码 ( 会 隐藏 其他 的 功能 界面 模块 )alt+shift+F 将 当前 文件 加入 收藏夹 ctrl+alt+s 打开 配置 窗口 ctrl+tab 切换 代码 选项卡 ( 还要 进行 此 选择 , 效率 差些 )alt+ 切换 代码 选项卡 ctrl+F4 关闭 当前 代码 选项卡 代码 编辑 ctrl+D 复制 当前 行 ctrl+W 选中 单词 ctrl+ 以 单词 作为 边界 跳 光标 位置 alt+Insert 新建 一个 文件 或 其他 ctrl+alt+L 格式化 代码 shift+tab/tab 减少 / 扩大 缩进 ( 可以 在 代码 中 减少 行 缩进 )ctrl+Y 删除 一行 shift+enter 重新 开始 一行 ( 无论 光标 在 哪个 位置 ) 导航 esc 进入 代码 编辑 区域 alt+F1 查找 代码 在 其他 界面 模块 的 位置 , 颇为 有用 ctrl+G 到 指定 行 的 代码 ctrl+]/[ 光标 到 代码 块 的 前面 或 后面 alt+up/down 上 一个 / 下 一个 方法 建议 配置 版本控制 快捷键 ctrl+C 提交 代码 ctrl+p 向 远程 版本 库 推送 更新 ctrl+G 到 指定 行 的 代码 ctrl+]/[ 光标 到 代码 块 的 前面 或 后面 alt+up/down 上 一个 / 下 一个 方法 Webstorm 个人 设置 ###1. 提问 个 关于 webstorm 如何 禁用 版本控制 的 通知 File => Settings => Version Control => 在 右侧 找到 你 当前 的 项目 , 设置 VCS 为 none###2. 禁用 系统 或 插件 更新 设置 => 常规 => 更新 ###3. 端口号 设置 想 在 手机 端 访问 webstorm 做出 的 页面 , 遇到 了 根据 IP 地址 访问 页面 错误 的 问题 , 试 了 网上 的 方法 :“ 设置 webstorm 可以 被 外部 连接 访问 ”, 依旧 不能 解决 解决 方法 : 在 webstorm 下 :ctrl+alt+s 调出 设置 :###4. 关于 compass + scss 如果 本地 配置 了 config.rb 文件 , 加载 compass。 只 需要 file watcher compass+scss 即可 , 加载 本地 配置文件 。###5. 关于 scss 如何 关闭 自动 保存 compass Scss 关闭 同步 选项 (Immediate file synchronization)6. 配置 scss, 开启 Scss 的 Source Maps 功能 配置 SCSS, 如 配置 了 compass+scss 将 依赖 config.rb。 不 需要 再 配置 scss 本地 安装 好 SCSS 后 , 用 WebStorm 工具 新建 一个 '*.scss' 文件 , 就 会 自动 提醒 是否 'Add watcher', 直接 点击 一下 就 OK 啦 ; 前提 是 要 本 机 安装 了 Ruby 和 SCSS 才 行 ; 这样 WebStorm 就 会 自动 新建 一个 scss 的 'watcher':WebStorm 开启 Scss 的 Source Maps 功能 现在 , 当 我们 在 项目 里 新建 一个 'style.scss' 后 ,WebStorm 就 会 自动 也 生成 一个 'style.css'; 因为 , 我们 是 想要 把 'style.css.map' 文件 也 一起 生成 , 所以 需要 修改 'SCSS' 的 'File Watcher';ctrl + alt + s, 打开 'Settings'--'File Watchers', 然后 双击 'SCSS': 下面 是 默认 的 'SCSS File Watcher'WebStorm 开启 Scss 的 Source Maps 功能 修改 下面 两个 地方 就 可以 一起 生成 '*.map' 文件 啦 :'Arguments': --no-cache --update $FileName$:$FileNameWithoutExtension$.css 修改 后 :'Arguments': --no-cache --update --sourcemap --watch $FileName$:$FileNameWithoutExtension$.css 另 一处 :'Output paths to refresh': $FileNameWithoutExtension$.css 修改 后 :'Output paths to refresh': $FileNameWithoutExtension$.css:$FileNameWithoutExtension$.css.mapOK, 修改 完 保存 , 现在 新建 'style.scss' 后 就 会 自动 生成 'style.css' 和 'style.css.map' 啦 :WebStorm 开启 Scss 的 Source Maps 功能 WebStorm 开启 Scss 的 Source Maps 功能 如果 , 想 把 SCSS 源文件 与 生成 后 的 CSS 和 map 文件 分开 目录 , 则 如下 设置 :'Arguments': --no-cache --update --sourcemap --watch $FileName$:$FileParentDir$\\css\\$FileNameWithoutExtension$.css","title":"vscode webstorm sublime Eclipse 配置 ","oriTitle":"vscode webstorm sublime Eclipse 配置"}]