node

node

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
javascript/jQuery

javascript/jQuery

一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。
MongoDB

MongoDB

MongoDB 是一个基于分布式文件存储的数据库
openstack

openstack

OpenStack是一个由NASA(美国国家航空航天局)和Rackspace合作研发并发起的,以Apache许可证授权的自由软件和开放源代码项目。
VUE

VUE

一套构建用户界面的渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计。
bootstrap

bootstrap

Bootstrap is the most popular HTML, CSS, and JS framework for developing responsive, mobile first projects on the web.
HTML

HTML

超文本标记语言,标准通用标记语言下的一个应用。
CSS/SASS/SCSS/Less

CSS/SASS/SCSS/Less

层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言。
PHP

PHP

PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言。语法吸收了C语言、Java和Perl的特点,利于学习,使用广泛,主要适用于Web开发领域。PHP 独特的语法混合了C、Java、Perl以及PHP自创的语法。它可以比CGI或者Perl更快速地执行动态网页。用PHP做出的动态页面与其他的编程语言相比,PHP是将程序嵌入到HTML(标准通用标记语言下的一个应用)文档中去执行,执行效率比完全生成HTML标记的CGI要高许多;PHP还可以执
每天进步一点点

每天进步一点点

乌法把门的各累笑寂静
求职招聘

求职招聘

猎头招聘专用栏目
Python

Python

一种解释型、面向对象、动态数据类型的高级程序设计语言。

HTML5 实现手机拍照上传

HTMLlopo1983 发表了文章 • 0 个评论 • 2412 次浏览 • 2016-08-30 11:11 • 来自相关话题

页面样式:上传图片有原生的方法<input type="file" accept="image/*">,如果只想要拍照上传,不希望用户选择图片上传,可以通过添加capture属性,该属性值有camcorder/microphone/camera...,此处选择camera。
PS:该属性存在浏览器兼容性问题,不是所有的浏览器都支持。
<input type="file" accept="image/*" capture="camera" >因为原生file样式不满足要求,需要进行相应的处理,此时使用定位,在input上面放置我们想要的页面效果。然后当点击上面的元素,就可以触发我们的input进行图片上传。此时的问题是:当点击input上面的元素,需要事件穿透,即相当于点击input。则借助于css3新属性pointer-events。
button{
cursor:pointer;
pointer-events:none;
}----此时图片上传的样式已经处理好了
----代码片段:
<style >
*{
padding: 0;
margin: 0;
}
.wrapper{
width: 320px;
height: 50px;
margin: 20px auto;
position: relative;
border: 1px solid #f0f0f0;
}
input{
width: 100px;
height: 30px;
}
button{
position: absolute;
cursor: pointer;
pointer-events: none;
width: 100px;
height: 30px;
left: 0;
top: 0;
}
a{
pointer-events: none;
}
.img{
border: 1px solid #ccc;
padding: 10px;
}
</style >

<div class = "wrapper">
<input type = "file" accept= "image/*" capture= "camera" id= "img" />
<button >上传照片 </button >
</div >
?
图片压缩处理:
因为要做的是手机拍照上传,现在的手机拍照片都很大,比如小米4S,大小在3M以上,如果原图上传,太消耗用户流量,于是要解决图片压缩的问题。
通过change事件,监听图片上传,通过readerAsDataURL获取上传的图片。
document.getElementById( 'img').addEventListener( 'change', function () {
var reader = new FileReader();
reader.onload = function (e) {
//调用图片压缩方法:compress();
};
reader.readAsDataURL(this.files[0]);
console.log(this.files[0]);
var fileSize = Math.round( this.files[0].size/1024/1024) ; //以M为单位
//this.files[0] 该信息包含:图片的大小,以byte计算 获取size的方法如下:this.files[0].size;
}, false);对上传的图片进行压缩,需要借助于canvas API,调用其中canvas.toDataURL(type,?encoderOptions);?将图片按照一定的压缩比进行压缩,得到base64编码。重点来了:压缩策略:先设置图片的最大宽度 or 最大高度,一般设置其中一个就可以了,因为所有的手机宽高比差别不是很大。然后设置图片的最大size,allowMaxSize,根据图片的实际大小和最大允许大小,设置相应的压缩比率。
//最终实现思路:
1、设置压缩后的最大宽度 or 高度;
2、设置压缩比例,根据图片的不同size大小,设置不同的压缩比。

function compress(res,fileSize) { //res代表上传的图片,fileSize大小图片的大小
var img = new Image(),
maxW = 640; //设置最大宽度

img.onload = function () {
var cvs = document.createElement( 'canvas'),
ctx = cvs.getContext( '2d');

if(img.width > maxW) {
img.height *= maxW / img.width;
img.width = maxW;
}

cvs.width = img.width;
cvs.height = img.height;

ctx.clearRect(0, 0, cvs.width, cvs.height);
ctx.drawImage(img, 0, 0, img.width, img.height);

var compressRate = getCompressRate(1,fileSize);

var dataUrl = cvs.toDataURL( 'image/jpeg', compressRate);

document.body.appendChild(cvs);
console.log(dataUrl);
}

img.src = res;
}

function getCompressRate(allowMaxSize,fileSize){ //计算压缩比率,size单位为MB
var compressRate = 1;

if(fileSize/allowMaxSize > 4){
compressRate = 0.5;
} else if(fileSize/allowMaxSize >3){
compressRate = 0.6;
} else if(fileSize/allowMaxSize >2){
compressRate = 0.7;
} else if(fileSize > allowMaxSize){
compressRate = 0.8;
} else{
compressRate = 0.9;
}

return compressRate;
}
?
图片上传给服务器:图片已经压缩完成了,但是压缩后的图片不是File,而是一个base64编码,于是乎两个选择:1、以String的形式将base64编码上传给服务器,服务器转存base64为img图片;2、前端将base64转为File图片类型,上传给服务器。
方法一:压缩之后直接上传base64给后台,实现简单。
方法二:前端自己转存base64位File图片,这个对于前端 压力比较大。

原因:html5 canvas属于客户端API,没有权限去保存图片到硬盘,只有canvas.toDataURL()这一接口可导出画布的base64编码,以提供给服务器进行处理保存。所以如果要将base64编码转成图片需要借助于nodeJs。因为nodeJS有相关文件处理的API。
//使用nodeJS将base64转化成图片
var express = require('express');
var fs = require("fs");
var app = module.exports = express();

function dataToImage(dataUrl){
var base64Data = dataUrl.replace(/^data:image\/\w+;base64,/,'');
var dataBuffer = new Buffer(base64Data,'base64');

fs.writeFile('out.jpg',dataBuffer,function(err){
if(err){
console.log(err);
}else{
console.log('Success...');
}
});
}

dataToImage('data:image/jpeg;base64,/9...'); //图片完整base64过长,所以省略...

if(!module.parent){
app.listen(8000);
console.log('Express started on port 8000');
}Summary:如果使用nodeJS,需要单独部署nodeJS代码到服务器,整个逻辑会比较麻烦。综合比较两种方法,推荐使用第一种方法,直接传base64给服务器,后台处理相应的转化! 查看全部
页面样式:上传图片有原生的方法<input type="file" accept="image/*">,如果只想要拍照上传,不希望用户选择图片上传,可以通过添加capture属性,该属性值有camcorder/microphone/camera...,此处选择camera。
PS:该属性存在浏览器兼容性问题,不是所有的浏览器都支持。
<input type="file" accept="image/*" capture="camera" >
因为原生file样式不满足要求,需要进行相应的处理,此时使用定位,在input上面放置我们想要的页面效果。然后当点击上面的元素,就可以触发我们的input进行图片上传。此时的问题是:当点击input上面的元素,需要事件穿透,即相当于点击input。则借助于css3新属性pointer-events。
button{
cursor:pointer;
pointer-events:none;
}
----此时图片上传的样式已经处理好了
----代码片段:
<style >
*{
padding: 0;
margin: 0;
}
.wrapper{
width: 320px;
height: 50px;
margin: 20px auto;
position: relative;
border: 1px solid #f0f0f0;
}
input{
width: 100px;
height: 30px;
}
button{
position: absolute;
cursor: pointer;
pointer-events: none;
width: 100px;
height: 30px;
left: 0;
top: 0;
}
a{
pointer-events: none;
}
.img{
border: 1px solid #ccc;
padding: 10px;
}
</style >

<div class = "wrapper">
<input type = "file" accept= "image/*" capture= "camera" id= "img" />
<button >上传照片 </button >
</div >

?
图片压缩处理:
因为要做的是手机拍照上传,现在的手机拍照片都很大,比如小米4S,大小在3M以上,如果原图上传,太消耗用户流量,于是要解决图片压缩的问题。
通过change事件,监听图片上传,通过readerAsDataURL获取上传的图片。
document.getElementById( 'img').addEventListener( 'change', function () {
var reader = new FileReader();
reader.onload = function (e) {
//调用图片压缩方法:compress();
};
reader.readAsDataURL(this.files[0]);
console.log(this.files[0]);
var fileSize = Math.round( this.files[0].size/1024/1024) ; //以M为单位
//this.files[0] 该信息包含:图片的大小,以byte计算 获取size的方法如下:this.files[0].size;
}, false);
对上传的图片进行压缩,需要借助于canvas API,调用其中canvas.toDataURL(type,?encoderOptions);?将图片按照一定的压缩比进行压缩,得到base64编码。重点来了:压缩策略:先设置图片的最大宽度 or 最大高度,一般设置其中一个就可以了,因为所有的手机宽高比差别不是很大。然后设置图片的最大size,allowMaxSize,根据图片的实际大小和最大允许大小,设置相应的压缩比率。
//最终实现思路:
1、设置压缩后的最大宽度 or 高度;
2、设置压缩比例,根据图片的不同size大小,设置不同的压缩比。

function compress(res,fileSize) { //res代表上传的图片,fileSize大小图片的大小
var img = new Image(),
maxW = 640; //设置最大宽度

img.onload = function () {
var cvs = document.createElement( 'canvas'),
ctx = cvs.getContext( '2d');

if(img.width > maxW) {
img.height *= maxW / img.width;
img.width = maxW;
}

cvs.width = img.width;
cvs.height = img.height;

ctx.clearRect(0, 0, cvs.width, cvs.height);
ctx.drawImage(img, 0, 0, img.width, img.height);

var compressRate = getCompressRate(1,fileSize);

var dataUrl = cvs.toDataURL( 'image/jpeg', compressRate);

document.body.appendChild(cvs);
console.log(dataUrl);
}

img.src = res;
}

function getCompressRate(allowMaxSize,fileSize){ //计算压缩比率,size单位为MB
var compressRate = 1;

if(fileSize/allowMaxSize > 4){
compressRate = 0.5;
} else if(fileSize/allowMaxSize >3){
compressRate = 0.6;
} else if(fileSize/allowMaxSize >2){
compressRate = 0.7;
} else if(fileSize > allowMaxSize){
compressRate = 0.8;
} else{
compressRate = 0.9;
}

return compressRate;
}

?
图片上传给服务器:图片已经压缩完成了,但是压缩后的图片不是File,而是一个base64编码,于是乎两个选择:1、以String的形式将base64编码上传给服务器,服务器转存base64为img图片;2、前端将base64转为File图片类型,上传给服务器。
方法一:压缩之后直接上传base64给后台,实现简单。
方法二:前端自己转存base64位File图片,这个对于前端 压力比较大。

原因:html5 canvas属于客户端API,没有权限去保存图片到硬盘,只有canvas.toDataURL()这一接口可导出画布的base64编码,以提供给服务器进行处理保存。所以如果要将base64编码转成图片需要借助于nodeJs。因为nodeJS有相关文件处理的API。
//使用nodeJS将base64转化成图片
var express = require('express');
var fs = require("fs");
var app = module.exports = express();

function dataToImage(dataUrl){
var base64Data = dataUrl.replace(/^data:image\/\w+;base64,/,'');
var dataBuffer = new Buffer(base64Data,'base64');

fs.writeFile('out.jpg',dataBuffer,function(err){
if(err){
console.log(err);
}else{
console.log('Success...');
}
});
}

dataToImage('data:image/jpeg;base64,/9...'); //图片完整base64过长,所以省略...

if(!module.parent){
app.listen(8000);
console.log('Express started on port 8000');
}
Summary:如果使用nodeJS,需要单独部署nodeJS代码到服务器,整个逻辑会比较麻烦。综合比较两种方法,推荐使用第一种方法,直接传base64给服务器,后台处理相应的转化!

bootstrapTable index

bootstrap3.xlopo1983 回复了问题 • 2 人关注 • 1 个回复 • 1985 次浏览 • 2016-08-22 14:03 • 来自相关话题

前端装逼指南

扯蛋lopo1983 发表了文章 • 0 个评论 • 1685 次浏览 • 2016-08-22 13:56 • 来自相关话题

§ 开发

Macbook Pro 是标配,美其名曰“提高开发体验”
什么?你还在用 Spotlight?赶紧给我换 Alfred!

编辑器,Sublime / Atom / VS Code 三选一
虽然很想用IDE,但一定要忍住,并且与人解释道:
“启动速度慢,消耗资源多,不适合我这种完美主义者
如果不是为了美观,我宁愿使用 Vim / Emacs”

命令行 iTerm2 + Oh-my-zsh
二逼青年用 bash,普通青年用 zsh
我们也只是想做一名普通人罢了

查资料虽然都是百度
但一定要称都是用 Google
且要说英文而不是中文的“谷歌”
使用美式发音,当自己是湾区老司机

尽管四级飘过,六级没过
在 Stack Overflow 上点数也低
但也要说每天都与各国程序员谈笑风生

§ 语言

这年头如果还不用 Babel + ES6
都不好意思说自己是 JSer
当然还有 TypeScript / CoffeeScript / Dart …
没学过没关系
对外人说自己“略懂”即可
反正最后都是编译为 ES5,你懂的

为了避免对方深入问
此时你应该继续发表高见:
“JS 是基于原型的函数式弱类语言
引入类与强类真的是不伦不类”
说到此,顿一下,表现出百感交集
随后继续徐徐道:
“可大势所趋,吾等小辈惟随波逐流”
说罢,即可挥挥衣袖转身离去

在这里不得不提一下,虽然使用 Babel 转码可以尽情装逼
但其对某些新特性的转换相当二逼(详情请看这篇文章)
一句话:Babel 虽好,但别贪杯哦(推荐Babel 在线实时编译)

§ 代码风格

摒 弃JSLint / JSHint / JSCS,拥抱 ESLint
尽管平时只是个搬砖的
但时刻以世界顶级企业的规范约束自己
于是?eslint-config-airbnb?成了我们的标配

一般新手是这样写的:

/* Low */
if (a) {
return b;
} else {
return c;
}

逼格稍微高一点的这样写:

/* Bigger */
if (a) return b; // 提前结束,免用大括号与else
return c;

实际上还能更进一步:

/* Bigger than bigger */
① return a ? b : c // 不要写分号,留白予人想象的空间
② return a && b || c

总而言之,代码越短,可读性越差,逼格越高
不能让人随便看懂,就像人不能轻易让人看透

§ 奇技淫巧

罄竹难书

§ 常用库
DOM库

标配是 jQuery,手机端有 Zepto 作为替代品
想要装逼且不怕坑,那就上 Mootools
Prototype?嗯,复古的逼格都是很高的

一定要说自己纯粹为了优雅简洁,不得不用 jQuery
(如何做到 jQuery-free,请看这篇文章)

当然,就算是写 jQuery
也能体现出逼格
我们来看看新手一般是怎么写的:

/* Low */
var value = $(".container .myInput1").val();
$(".container .myInput2").val(value);
$(".container .myInput3").attr("disabled", "disabled");

用双引号,以及对选择器性能认知不足,是新手的特征
一般直接使用类选择器的,都是对用户体验很有自信的

/* Bigger */
// 把div.container命名为myDiv
var $myDiv = $('#myDiv'), // 缓存DOM
v = $myDiv.find('.myInput1').val();
?
$myDiv
.find('.myInput2').val(v)
.end() // 坚持链式调用
.find('.myInput3').attr('disabled', 'disabled');

(有关 jQuery 选择器的性能以及最佳实践,请看这篇文章)

UI

BootStrap 烂大街
不是我们的菜
我们选择的标准是门槛要高
于是
Foundation6 / Ant Design
映入眼帘

请谨慎使用
Semantic UI / UIkit / Amaze UI …
避免不能自拔

工具库

后浪 lodash 把前浪 underscore 拍死在沙滩上
于是它成了唯一的选择
不过为了保持逼格
我们要尽量使用原汁原味的 ES6
就算要用也一定要注意素质:

/* Low */
import _ from 'lodash' // 把整个lodash打包进去了

/* Bigger */
import isEmpty from 'lodash/isEmpty' // 仅把个别函数打包

模板引擎

逼格最高显然是 Jade
但改名为 Pug(哈巴狗)后
就像是小龙女被尹志平不可描述后
再也无爱了
从此以后
留了胡子(Mustache)
扶着把手(Handlebars)
默默耕耘

异步编程

这里不谈 Q / Bluebird / Async / co / then 等库
皆因Babel已经支持所有的异步编程解决方案
当前最常用的还是Promise

有些新手会写出这种代码:

/* Low */
// 找出与用户1同市的所有用户
User.findById(1).then((user) => {
User.find({ city: user.city }).then((users) => {
res.json(users.toJSON())
})
})

这属于 Promise反模式,与回调函数无异

/* Bigger */
User.findById(1).then((user) => {
return User.find({ city: user.city }) // 返回Promise
}).then((users) => {
res.json(users.toJSON())
}).catch(next)

§ 包管理工具

如果你被
Bower / spm / Component / Duo …
坑过
请回到 npm 的怀抱
什么?jspm?有完没完…

§ 构建工具

想当年我不懂什么是自动构建工具
他们说:生命苦短,我们用 Grunt

好不容易用上 Grunt 的时候
他们又说:Gulp 基于流,符合 Unix 哲学

之后我虔诚地换上了 Gulp
他们双说:Webpack 最好用

最后终于用上了 Webpack
他们叒说:FIS3 约不约?。。。

§ 模块化方案

无论是

RequireJS (AMD)
SeaJS (CMD)
KMD.js (KMD)
Browserify (CommonJS)


最后都庆幸回归到 npm + Webpack
什么?SystemJS?有完没完…

§ MV*框架 / 技术栈 / 大型框架
Backbone

每个人都有一段不堪回首的经历
就像当年在 QQ 空间发“你若安好便是晴天”的说说
Backbone就是这样子的存在

Angular

一定要边吐槽边用,不然就一点都不 ng 了
“学习曲线陡峭”不应从你口中说出
“学习过程趣味盎然”才是你的菜

Vue

一定要用“优雅”来形容
就像用 ES6 一定要“大胆”

React技术栈

React 已经是前端高逼格的代名词
所以无论懂不懂都要喊:
“React 大法好”
因为这是一种信仰
称赞 JSX 的标新立异
谈谈 Flux / Redux
扯扯 Elm / RxJS
每到深入则戛然而止:
“太深入的太抽象,你们未必能理解”
由此,听者只会更加崇拜你

其他

还有国内相对小众的 Ember / Knockout / Avalon
(请别再把 YUI / Dojo / Ext / KISSY 扯进来了好伐)

§ 混合 / 原生开发

自从 PhoneGap 出来后
貌似我们也能抢 安卓/iOS 的饭碗了
Ionic 更是将 Hybrid APP 推向高潮

不过混合始终比不上原生
于是 React Native 应运而生
最近多了一个新的选择:Weex

别忘了还有桌面的 nw.js 以及 Electron

JSer从一入门开始,就掌握了改变世界的能力
也比其他程序员更容易走向人生的巅峰

§ 后端框架

我们一直标榜自己是全栈
不玩几下后端框架怎么行

快递员用 Express
风湿患者用 Koa
哲学家用 ThinkJS
水手用 Sails

还有全栈的 Meteor
上述都用一遍
相信也快转行了

§ 服务器进程管理

既然都玩上了后端框架
不懂部署服务器怎么行

二逼青年用 supervisor / nodemon
文艺青年用 forever
普通青年用 pm2
装逼青年用 Tmux + node 查看全部
§ 开发

Macbook Pro 是标配,美其名曰“提高开发体验”
什么?你还在用 Spotlight?赶紧给我换 Alfred!

编辑器,Sublime / Atom / VS Code 三选一
虽然很想用IDE,但一定要忍住,并且与人解释道:
“启动速度慢,消耗资源多,不适合我这种完美主义者
如果不是为了美观,我宁愿使用 Vim / Emacs”

命令行 iTerm2 + Oh-my-zsh
二逼青年用 bash,普通青年用 zsh
我们也只是想做一名普通人罢了

查资料虽然都是百度
但一定要称都是用 Google
且要说英文而不是中文的“谷歌”
使用美式发音,当自己是湾区老司机

尽管四级飘过,六级没过
在 Stack Overflow 上点数也低
但也要说每天都与各国程序员谈笑风生

§ 语言

这年头如果还不用 Babel + ES6
都不好意思说自己是 JSer
当然还有 TypeScript / CoffeeScript / Dart …
没学过没关系
对外人说自己“略懂”即可
反正最后都是编译为 ES5,你懂的

为了避免对方深入问
此时你应该继续发表高见:
“JS 是基于原型的函数式弱类语言
引入类与强类真的是不伦不类”
说到此,顿一下,表现出百感交集
随后继续徐徐道:
“可大势所趋,吾等小辈惟随波逐流”
说罢,即可挥挥衣袖转身离去

在这里不得不提一下,虽然使用 Babel 转码可以尽情装逼
但其对某些新特性的转换相当二逼(详情请看这篇文章)
一句话:Babel 虽好,但别贪杯哦(推荐Babel 在线实时编译)

§ 代码风格

摒 弃JSLint / JSHint / JSCS,拥抱 ESLint
尽管平时只是个搬砖的
但时刻以世界顶级企业的规范约束自己
于是?eslint-config-airbnb?成了我们的标配

一般新手是这样写的:

/* Low */
if (a) {
return b;
} else {
return c;
}

逼格稍微高一点的这样写:

/* Bigger */
if (a) return b; // 提前结束,免用大括号与else
return c;

实际上还能更进一步:

/* Bigger than bigger */
① return a ? b : c // 不要写分号,留白予人想象的空间
② return a && b || c

总而言之,代码越短,可读性越差,逼格越高
不能让人随便看懂,就像人不能轻易让人看透

§ 奇技淫巧

罄竹难书

§ 常用库
DOM库

标配是 jQuery,手机端有 Zepto 作为替代品
想要装逼且不怕坑,那就上 Mootools
Prototype?嗯,复古的逼格都是很高的

一定要说自己纯粹为了优雅简洁,不得不用 jQuery
(如何做到 jQuery-free,请看这篇文章)

当然,就算是写 jQuery
也能体现出逼格
我们来看看新手一般是怎么写的:

/* Low */
var value = $(".container .myInput1").val();
$(".container .myInput2").val(value);
$(".container .myInput3").attr("disabled", "disabled");

用双引号,以及对选择器性能认知不足,是新手的特征
一般直接使用类选择器的,都是对用户体验很有自信的

/* Bigger */
// 把div.container命名为myDiv
var $myDiv = $('#myDiv'), // 缓存DOM
v = $myDiv.find('.myInput1').val();
?
$myDiv
.find('.myInput2').val(v)
.end() // 坚持链式调用
.find('.myInput3').attr('disabled', 'disabled');

(有关 jQuery 选择器的性能以及最佳实践,请看这篇文章)

UI

BootStrap 烂大街
不是我们的菜
我们选择的标准是门槛要高
于是
Foundation6 / Ant Design
映入眼帘

请谨慎使用
Semantic UI / UIkit / Amaze UI …
避免不能自拔

工具库

后浪 lodash 把前浪 underscore 拍死在沙滩上
于是它成了唯一的选择
不过为了保持逼格
我们要尽量使用原汁原味的 ES6
就算要用也一定要注意素质:

/* Low */
import _ from 'lodash' // 把整个lodash打包进去了

/* Bigger */
import isEmpty from 'lodash/isEmpty' // 仅把个别函数打包

模板引擎

逼格最高显然是 Jade
但改名为 Pug(哈巴狗)后
就像是小龙女被尹志平不可描述后
再也无爱了
从此以后
留了胡子(Mustache)
扶着把手(Handlebars)
默默耕耘

异步编程

这里不谈 Q / Bluebird / Async / co / then 等库
皆因Babel已经支持所有的异步编程解决方案
当前最常用的还是Promise

有些新手会写出这种代码:

/* Low */
// 找出与用户1同市的所有用户
User.findById(1).then((user) => {
User.find({ city: user.city }).then((users) => {
res.json(users.toJSON())
})
})

这属于 Promise反模式,与回调函数无异

/* Bigger */
User.findById(1).then((user) => {
return User.find({ city: user.city }) // 返回Promise
}).then((users) => {
res.json(users.toJSON())
}).catch(next)

§ 包管理工具

如果你被
Bower / spm / Component / Duo …
坑过
请回到 npm 的怀抱
什么?jspm?有完没完…

§ 构建工具

想当年我不懂什么是自动构建工具
他们说:生命苦短,我们用 Grunt

好不容易用上 Grunt 的时候
他们又说:Gulp 基于流,符合 Unix 哲学

之后我虔诚地换上了 Gulp
他们双说:Webpack 最好用

最后终于用上了 Webpack
他们叒说:FIS3 约不约?。。。

§ 模块化方案

无论是

RequireJS (AMD)
SeaJS (CMD)
KMD.js (KMD)
Browserify (CommonJS)


最后都庆幸回归到 npm + Webpack
什么?SystemJS?有完没完…

§ MV*框架 / 技术栈 / 大型框架
Backbone

每个人都有一段不堪回首的经历
就像当年在 QQ 空间发“你若安好便是晴天”的说说
Backbone就是这样子的存在

Angular

一定要边吐槽边用,不然就一点都不 ng 了
“学习曲线陡峭”不应从你口中说出
“学习过程趣味盎然”才是你的菜

Vue

一定要用“优雅”来形容
就像用 ES6 一定要“大胆”

React技术栈

React 已经是前端高逼格的代名词
所以无论懂不懂都要喊:
“React 大法好”
因为这是一种信仰
称赞 JSX 的标新立异
谈谈 Flux / Redux
扯扯 Elm / RxJS
每到深入则戛然而止:
“太深入的太抽象,你们未必能理解”
由此,听者只会更加崇拜你

其他

还有国内相对小众的 Ember / Knockout / Avalon
(请别再把 YUI / Dojo / Ext / KISSY 扯进来了好伐)

§ 混合 / 原生开发

自从 PhoneGap 出来后
貌似我们也能抢 安卓/iOS 的饭碗了
Ionic 更是将 Hybrid APP 推向高潮

不过混合始终比不上原生
于是 React Native 应运而生
最近多了一个新的选择:Weex

别忘了还有桌面的 nw.js 以及 Electron

JSer从一入门开始,就掌握了改变世界的能力
也比其他程序员更容易走向人生的巅峰

§ 后端框架

我们一直标榜自己是全栈
不玩几下后端框架怎么行

快递员用 Express
风湿患者用 Koa
哲学家用 ThinkJS
水手用 Sails

还有全栈的 Meteor
上述都用一遍
相信也快转行了

§ 服务器进程管理

既然都玩上了后端框架
不懂部署服务器怎么行

二逼青年用 supervisor / nodemon
文艺青年用 forever
普通青年用 pm2
装逼青年用 Tmux + node

jquery-ui-autocomplete+Bootstrap modal 层级问题

bootstrap3.xlopo1983 发表了文章 • 0 个评论 • 2141 次浏览 • 2016-08-22 11:27 • 来自相关话题

.ui-autocomplete{
display:block;
z-index:99999;
}
.ui-autocomplete{
display:block;
z-index:99999;
}

bootstrap+swiper 全文图片预览

bootstrap3.xlopo1983 发表了文章 • 0 个评论 • 1849 次浏览 • 2016-08-16 15:26 • 来自相关话题

$('#product-info .pro-img img').click(function() {
var $index = $(this).index();
var temp = '<div class="modal fade" id="modalSwiper" tabindex="-1"><div class="modal-dialog modal-full" role="document"><div class="modal-content"><div class="modal-body"><div class="swiper-container" id="modSwiper"><div class="swiper-wrapper"></div><div class="swiper-pagination"></div><div class="swiper-button-prev iconfont icon-left"></div><div class="swiper-button-next iconfont icon-right"></div></div></div></div></div></div>';
$('body').append(temp);
var tempslider = '';
$('#product-info .pro-img img').each(function() {
tempslider += '<div class="swiper-slide"><img src="' + $(this).attr('src') + '" class="img-responsive center-block" alt="" /></div>';
});
$('#modalSwiper').find('.swiper-wrapper').append(tempslider);
var modalSwiper = $('#modSwiper').swiper({
autoplay: 4000,
speed: 1500,
loop: true,
pagination: '.swiper-pagination',
lazyLoading: true,
paginationClickable: true,
runCallbacksOnInit: true,
prevButton: '.swiper-button-prev',
nextButton: '.swiper-button-next',
});
$('#modalSwiper').modal('show');
$('#modalSwiper').on('shown.bs.modal', function() {
var a = $('#modalSwiper .modal-full').height(),
b = $('#modalSwiper .modal').height();
if(a < b) {
$('#modalSwiper .modal-full').css('transform', 'translate(0,' + (b - a) / 2 + ')')
}
modalSwiper.update(true);
modalSwiper.slideTo($index + 1,500);
});
$('#modalSwiper').on('hidden.bs.modal', function() {
$('#modalSwiper').remove();
})
}) 查看全部
$('#product-info .pro-img img').click(function() {
var $index = $(this).index();
var temp = '<div class="modal fade" id="modalSwiper" tabindex="-1"><div class="modal-dialog modal-full" role="document"><div class="modal-content"><div class="modal-body"><div class="swiper-container" id="modSwiper"><div class="swiper-wrapper"></div><div class="swiper-pagination"></div><div class="swiper-button-prev iconfont icon-left"></div><div class="swiper-button-next iconfont icon-right"></div></div></div></div></div></div>';
$('body').append(temp);
var tempslider = '';
$('#product-info .pro-img img').each(function() {
tempslider += '<div class="swiper-slide"><img src="' + $(this).attr('src') + '" class="img-responsive center-block" alt="" /></div>';
});
$('#modalSwiper').find('.swiper-wrapper').append(tempslider);
var modalSwiper = $('#modSwiper').swiper({
autoplay: 4000,
speed: 1500,
loop: true,
pagination: '.swiper-pagination',
lazyLoading: true,
paginationClickable: true,
runCallbacksOnInit: true,
prevButton: '.swiper-button-prev',
nextButton: '.swiper-button-next',
});
$('#modalSwiper').modal('show');
$('#modalSwiper').on('shown.bs.modal', function() {
var a = $('#modalSwiper .modal-full').height(),
b = $('#modalSwiper .modal').height();
if(a < b) {
$('#modalSwiper .modal-full').css('transform', 'translate(0,' + (b - a) / 2 + ')')
}
modalSwiper.update(true);
modalSwiper.slideTo($index + 1,500);
});
$('#modalSwiper').on('hidden.bs.modal', function() {
$('#modalSwiper').remove();
})
})

群规2018

bootstrap3.xlopo1983 发表了文章 • 0 个评论 • 3295 次浏览 • 2016-07-30 18:51 • 来自相关话题

1.进群请改名称为 地区-称呼的格式
(为同城交流更为便捷,望大家自觉准守)。?
2.请尊重群内其他群员,上班期间尽量少聊与群主题无关的内容,恶意发大图刷屏(除了qq自带表情外其他的一律视为大图),上班时间请勿红包刷屏(禁令时间为: 周一 ~ 周五 8:30~12:00 13:00~17:30 ),发引导用户注册的AD链接直接飞机。
3.问问题前,请先baidu和查看api无果后再提问,问问题时 请尽量图文并茂,以节约时间!bootstrap相关的问题,请先申明版本号(呵呵!本群不再讨论兼容问题)。
4.若提问暂时没人回答,可到www.bsfans.com/wenda/ 留言或查看是否有和你一样的问题已被解答,不要随意@别人,你忙别人也忙!
5.群内禁止发黄赌毒 反党反社会的言论 图片
6.猎头、招聘请到www.bsfans.com/wenda/ 发布,若急需发布的可联系群主!?
以上规定违反者 送禁言套餐一份 若多次再犯送全球通单程机票一张!
? 查看全部
1.进群请改名称为 地区-称呼的格式
(为同城交流更为便捷,望大家自觉准守)。?
2.请尊重群内其他群员,上班期间尽量少聊与群主题无关的内容,恶意发大图刷屏(除了qq自带表情外其他的一律视为大图),上班时间请勿红包刷屏(禁令时间为: 周一 ~ 周五 8:30~12:00 13:00~17:30 ),发引导用户注册的AD链接直接飞机。
3.问问题前,请先baidu和查看api无果后再提问,问问题时 请尽量图文并茂,以节约时间!bootstrap相关的问题,请先申明版本号(呵呵!本群不再讨论兼容问题)。
4.若提问暂时没人回答,可到www.bsfans.com/wenda/ 留言或查看是否有和你一样的问题已被解答,不要随意@别人,你忙别人也忙!
5.群内禁止发黄赌毒 反党反社会的言论 图片
6.猎头、招聘请到www.bsfans.com/wenda/ 发布,若急需发布的可联系群主!?
以上规定违反者 送禁言套餐一份 若多次再犯送全球通单程机票一张!
?

最新群规2016 v1.2

回复

bootstrap3.xlopo1983 发起了问题 • 2 人关注 • 0 个回复 • 2904 次浏览 • 2016-07-06 09:33 • 来自相关话题

Fixalert

bootstrap3.xlopo1983 发表了文章 • 0 个评论 • 1730 次浏览 • 2016-07-28 15:25 • 来自相关话题

.alertbox {
position: fixed;
max-width: 480px;
min-width: 100px;
width: auto;
height: auto;
overflow: hidden;
.alert {
.unbdr;
.close {
margin-left: 15px;
}
}
&[data-pos="br"] {
right: 5px;
bottom: 0;
}
&[data-pos="tr"] {
right: 5px;
top: 100px;
}
a {
display: block;
cursor: pointer;
&:hover {
color: inherit;
}
}
}less?function fixAlert(a, b, c, d) {
//a 位置 0 右下 1 右上 | b 类型 0警告 1 错误 2正确 | c 内容 | d 如果有 者为url
$('.alertbox').remove();
var pos, type;
var temp = '';
var tempChild = '';
if (a == 0) {
pos = 'br';
} else {
pos = 'tr';
};
if (b == 0) {
type = "warning";
} else if (b == 1) {
type = "danger";
} else {
type = "success";
};
if (d == undefined) {
d = "javascript:;"
};
temp += '<div class="alertbox" data-pos="' + pos + '"></a>';
$('body').append(temp);
tempChild += '<a class="alert ' + type + '" href="' + d + '"><button type="button" class="close" data-dismiss="alert"><span>×</span></button>' + c + '</a>';
$('.alertbox').append(tempChild);
$('.alert').on('closed.bs.alert', function() {
$('.alertbox').remove();
});
};js
?
fixAlert(1,0,'警告的内容','http://www.baidu.com') 查看全部
.alertbox {
position: fixed;
max-width: 480px;
min-width: 100px;
width: auto;
height: auto;
overflow: hidden;
.alert {
.unbdr;
.close {
margin-left: 15px;
}
}
&[data-pos="br"] {
right: 5px;
bottom: 0;
}
&[data-pos="tr"] {
right: 5px;
top: 100px;
}
a {
display: block;
cursor: pointer;
&:hover {
color: inherit;
}
}
}
less?
function fixAlert(a, b, c, d) {
//a 位置 0 右下 1 右上 | b 类型 0警告 1 错误 2正确 | c 内容 | d 如果有 者为url
$('.alertbox').remove();
var pos, type;
var temp = '';
var tempChild = '';
if (a == 0) {
pos = 'br';
} else {
pos = 'tr';
};
if (b == 0) {
type = "warning";
} else if (b == 1) {
type = "danger";
} else {
type = "success";
};
if (d == undefined) {
d = "javascript:;"
};
temp += '<div class="alertbox" data-pos="' + pos + '"></a>';
$('body').append(temp);
tempChild += '<a class="alert ' + type + '" href="' + d + '"><button type="button" class="close" data-dismiss="alert"><span>×</span></button>' + c + '</a>';
$('.alertbox').append(tempChild);
$('.alert').on('closed.bs.alert', function() {
$('.alertbox').remove();
});
};
js
?
fixAlert(1,0,'警告的内容','http://www.baidu.com')

mAlert

bootstrap3.xlopo1983 发表了文章 • 0 个评论 • 1571 次浏览 • 2016-07-28 15:23 • 来自相关话题

//mAlert使用方法
//1 警告,2错误,3成功,4无状态 (c,a,b)c 状态 a 标题 b 内容 c为必填;
?
<a class="btn btn-success" onclick="mAlert(3,'成功的提示文字','成功')">成功</a>function mAlert(c, a, b, u) {
$('.modal').remove();
var m = '',
temp = '';
var mclass, micon;
var $md = $('#alertModal');
if (c == 1) {
mclass = ' warning';
micon = 'icon-war';
} else if (c == 2) {
mclass = ' danger';
micon = 'icon-erro';
} else if (c == 3) {
mclass = ' success';
micon = 'icon-suc';
} else if (c == undefined || c == 0) {
micon = 'icon-info'
};
temp += '<div class="modal fade' + mclass + '" id="alertModal" data-keyboard="false" tabindex="-1" role="dialog">';
temp += '<div class="modal-dialog modal-sm"><div class="modal-content">';
temp += '<div class="modal-body"><a class="close"></a><div class="media"><div class="media-left"><span class="iconplus ' + micon + '"></span></div>';
temp += '<div class="media-body media-middle"><h4>' + b + '</h4><p class="text-justify">' + a + '</p></div></div></div>';
temp += '<div class="modal-footer"><p><a class="btn btn-default btn-sm pull-right" data-dismiss="modal">确定</a></p></div>';
temp += '</div></div></div>';
$('body').append(temp);
$('#alertModal').modal({
show: 'true',
backdrop: 'static',
});
$('#alertModal').on('hidden.bs.modal', u)
}#alertModal {
.modal-header {
padding-top: 10px;
padding-bottom: 10px;
}
.modal-title {
color: @cwh;
margin: 0;
}
.modal-sm {
width: 400px;
}
.iconplus {
font-size: 96px;
}
.modal-body {
.btn {
padding-left: 25px;
padding-right: 25px;
}
p {
margin-bottom: 0;
}
.icon-erro {
color: @cre;
}
.icon-war {
color: @cye*0.9;
}
.icon-suc {
color: @cgr;
}
}
} 查看全部
//mAlert使用方法
//1 警告,2错误,3成功,4无状态 (c,a,b)c 状态 a 标题 b 内容 c为必填;
?
<a class="btn btn-success" onclick="mAlert(3,'成功的提示文字','成功')">成功</a>
function mAlert(c, a, b, u) {
$('.modal').remove();
var m = '',
temp = '';
var mclass, micon;
var $md = $('#alertModal');
if (c == 1) {
mclass = ' warning';
micon = 'icon-war';
} else if (c == 2) {
mclass = ' danger';
micon = 'icon-erro';
} else if (c == 3) {
mclass = ' success';
micon = 'icon-suc';
} else if (c == undefined || c == 0) {
micon = 'icon-info'
};
temp += '<div class="modal fade' + mclass + '" id="alertModal" data-keyboard="false" tabindex="-1" role="dialog">';
temp += '<div class="modal-dialog modal-sm"><div class="modal-content">';
temp += '<div class="modal-body"><a class="close"></a><div class="media"><div class="media-left"><span class="iconplus ' + micon + '"></span></div>';
temp += '<div class="media-body media-middle"><h4>' + b + '</h4><p class="text-justify">' + a + '</p></div></div></div>';
temp += '<div class="modal-footer"><p><a class="btn btn-default btn-sm pull-right" data-dismiss="modal">确定</a></p></div>';
temp += '</div></div></div>';
$('body').append(temp);
$('#alertModal').modal({
show: 'true',
backdrop: 'static',
});
$('#alertModal').on('hidden.bs.modal', u)
}
#alertModal {
.modal-header {
padding-top: 10px;
padding-bottom: 10px;
}
.modal-title {
color: @cwh;
margin: 0;
}
.modal-sm {
width: 400px;
}
.iconplus {
font-size: 96px;
}
.modal-body {
.btn {
padding-left: 25px;
padding-right: 25px;
}
p {
margin-bottom: 0;
}
.icon-erro {
color: @cre;
}
.icon-war {
color: @cye*0.9;
}
.icon-suc {
color: @cgr;
}
}
}

如何实现折叠菜单的正负号的图标的变化

javascript/jQuerylopo1983 回复了问题 • 2 人关注 • 1 个回复 • 1812 次浏览 • 2016-07-23 03:32 • 来自相关话题