於见

於见 查看完整档案

北京编辑天津工业大学  |  软件工程 编辑  |  填写所在公司/组织 segmentfault.com/u/yujianni 编辑
编辑

前端攻城狮

个人动态

於见 收藏了文章 · 2018-05-04

javascript有用的代码片段

JavaScript有用的代码片段

小数取整

const x = 1.234;
~~x    //1
x >>   //1
x | 0  //1
Math.floor(x)  //1

const y = -1.4;
x >>   //-1
Math.floor(y)   //-2
按位运算符直接去掉小数,Math.floor()向下取整,返回的数小于等于原来的数。

生成n位随机数

let getRandom = n => Math.random().toString().slice(-n);
getRandom(6)   //6位随机数

生成16进制颜色

let colorCode = '#' +('00000' +(Math .random()* 0x1000000 << 0).toString(16)).slice(- 6);

n到m间随机整数

let randomNum = (n,m) => Math.floor(Math.random()*(m-n) + n);
randomNum(2,10)   //2-10之间的整数
生成n到m间的随机整数,不包括m,n和m可以为负数。

驼峰命名转下划线

let humpToUnderline = str => str.match(/^[a-z][a-z0-9]+|[A-Z][a-z0-9]*/g).join('_').toLowerCase();
humpToUnderline('helloWorld');  //hello_world

url参数转json

let urlToJson = url => {
    let json = {};
    if (!!!url) return json;
    let data = url.split('?')[1] ? url.split('?')[1].split('&') : [];
    for(let i=0; i<data.length; i++) {
        let k = data[i].split('=');
        k[0] && (json[k[0]] = k[1] || '');
    }
    return json;
}

获取url中的参数

let getUrlData = name => {
    let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
    let r = window.location.search.substr(1).match(reg);
    if (r != null) return decodeURI(r[2]);
    return null;
}

n维数组转1维数组

let flatten = arr => JSON.parse(`[${JSON.stringify(arr).replace(/\[|]/g, '')}]`);
let flatten = arr => arr.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);
let flatten = a => Array.isArray(a) ? [].concat(...a.map(flatten)) : a;

flatten([1,[2,3,[3,4],5])  //[1,2,3,4,5]

n维数组展开成字符串

let arr = [1,3,[4,[72,'a','d'],3,[6,'c'],d]];

arr+'';
arr.toString();
arr.join();
JSON.stringify(arr).replace(/\[|\]/g,'');

//'1,3,4,72,"a","d",3,6,"c"'

时间格式化

//时间格式化
function format1(x, y) {
    let i = 0;
    var z = {
        y: x.getFullYear(),
        M: x.getMonth() + 1,
        d: x.getDate(),
        h: x.getHours(),
        m: x.getMinutes(),
        s: x.getSeconds()
    };
    return y.replace(/(y+|M+|d+|h+|m+|s+)/g, function(v) {
        console.log(++i);
        return ((v.length > 1 ? "0" : "") + eval('z.' + v.slice(-1))).slice(-(v.length > 2 ? v.length : 2))
    });
}

format1(new Date(), 'yyyy-MM-dd h:m:s');   //2018-01-22 9:38:10

统计文字个数

//统计文字个数
function wordCount(data) {
  var pattern = /[a-zA-Z0-9_\u0392-\u03c9]+|[\u4E00-\u9FFF\u3400-\u4dbf\uf900-\ufaff\u3040-\u309f\uac00-\ud7af]+/g;
  var m = data.match(pattern);
  var count = 0;
  if( m === null ) return count;
  for (var i = 0; i < m.length; i++) {
    if (m[i].charCodeAt(0) >= 0x4E00) {
      count += m[i].length;
    } else {
      count += 1;
    }
  }
  return count;
}

var text = '统计文字个数';
// console.log(wordCount(text)); // 6

格式化数字

//法一
function formatNum (str) {
    return str.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}

//法二
function formatNum (str) {
    return str.split('').reverse().reduce((prev, next, index) => {
        return ((index % 3) ? next : (next + ',')) + prev
    })
}

检测质数

function isPrime(n) {
    return !(/^.?$|^(..+?)\1+$/).test('1'.repeat(n))
}

统计字符出现的次数

function strTimes (str) {
    return str.split('').reduce((p,n) => (p[n]++ || (p[n]=1) ,p), {});   
}    

评级

let grade = rate => "★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate);

字符串类型的数字转数字

let a = '1';
+a   //1;
+a 可以理解为Number(a),将一个变量转成数字。布尔值返回0或1,undefined返回NaN,数字直接返回,null返回0,对于字符串,将其转换为十进制数值,会忽略前面的0(16进制除外),空字符串返回0,浮点数会返回浮点数值。其他格式字符串(无论是否数字开头,返回NaN,字符串中好几个小数点,返回NaN

数组去重复

[...new Set(arr)]

更多更详细的数组去重方法

获取时间戳

(new Date()).getTime();
(new Date).getTime();
new Date().getTime();
+new Date();
Date.now();
查看原文

於见 收藏了文章 · 2018-03-14

页面架构HTML+CSS ヾ(o◕∀◕)ノ 常用居中&多列布局

CSS Reset

1.作用

(1)清除浏览器默认样式
(2)全局样式定义

2.特别注意

(1)项目开发初期就定义好
(2)reset.css 在引入的时候一定要放在第一位
(3)不同的产品reset.css不一样

3.table合并边框间距

table {
  border-collapse: collapse; // 合并边框
  border-spacing: 0; //边框间距。当 `border-collapse` 值为 `seperate` 时生效

}

4.一个并不完整也并不通用的reset.css样例

    html,body,h1,h2,h3,h4,h5,h6,div,dl,dt,dd,ul,ol,li,p,blockquote,pre,hr,figure,table,caption,th,td,form,fieldset,legend,input,button,textarea,menu{margin:0;padding:0;}
    header,footer,section,article,aside,nav,hgroup,address,figure,figcaption,menu,details{display:block;}
    table{border-collapse:collapse;border-spacing:0;}
    caption,th{text-align:left;font-weight:normal;}
    html,body,fieldset,img,iframe,abbr{border:0;}
    i,cite,em,var,address,dfn{font-style:normal;}
    [hidefocus],summary{outline:0;}
    li{list-style:none;}
    h1,h2,h3,h4,h5,h6,small{font-size:100%;}
    sup,sub{font-size:83%;}
    pre,code,kbd,samp{font-family:inherit;}
    q:before,q:after{content:none;}
    textarea{overflow:auto;resize:none;}
    label,summary{cursor:default;}
    a,button{cursor:pointer;}
    h1,h2,h3,h4,h5,h6,em,strong,b{font-weight:normal;}
    del,ins,u,s,a,a:hover{text-decoration:none;}
    body,textarea,input,button,select,keygen,legend{font:12px/1.14 arial,simsun;color:#333;outline:0;}
    body{background:#fff;}
    a,a:hover{color:#333;}

布局解决方案

居中布局

1.水平居中

父元素和子元素宽度未知。

<div class="parent">
  <div class="child">child</div>
</div>

要达到的效果是这样:
图片描述

方法一:flex + justify-content

主要代码:

.parent { 
  display: flex;
  justify-content: center;
}

没啥好解释,直接看 神奇的flex实现栗子 吧 (~ ̄▽ ̄)~

方法二:absolute + transform

主要代码:

.parent { position: relative; }
.child { 
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

原理是:left: 50%;在子元素的左侧添加了一段距离,这段距离是父元素宽度的50%,接着因为translateX(50%) 设置百分比时的参照物是自身宽度,所以向左偏移了自身宽度的50%,就居中啦 ╮(‵▽′)╭

动动小手看看栗子

方法三:inline-block + text-align

主要代码:

.parent { text-align: center; }
.child { display: inline-block; }

这种方法有一个问题是:parent设置了text-align: center;后, 因为这个属性可继承,会导致child中的文字也会居中,而这个效果是我们未必需要的,所以我们很多时候需要在.child中加一句 text-align: left;

自己看看栗子

方法四:table + margin

主要代码:

.child { display: table; margin: 0 auto; }

table的特点:宽度为内容宽度 的块状元素,所以也可以用margin: 0 auto;居中。

优点:只设置子元素样式就可以了,不需关心父元素。

看看栗子

不喜欢这第四个方案,table是辣么有语义的一个样式,为什么随便把人家变成table ( ̄. ̄)

2.垂直居中

父元素和子元素高度未知。

意欲达到的效果:

图片描述

方法一:flex+ align-items

.parent {
  display: flex;
  align-items: center;
}

水平居中的方法一

栗子

方法二:absolute + transform

.parent { position: relative; }
.child {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

水平居中的方法二

栗子

方法三:table-cell + vertical-align

.parent {
  display: table-cell;
  vertical-align: middle;
}

vertical-align 可以作用在 inline元素,inline-table元素,以及table-cell元素上。

栗子

3.水平垂直居中

父元素和子元素宽高都未知。

图片描述

方法一:flex + justify-content + align-items

.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}

综合了水平居中垂直居中的方法一

栗子

方法二: absolute + transform

.parent { position: relative; }
.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

综合了水平居中垂直居中的方法二

栗子

方法三: absolute + margin: auto; (常用)

.parent { position: relative; }
.child {
  position: absolute;
  margin: auto;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

栗子

方法四:[inline-block + text-align] + [table-cell + vertical-align]

.parent {
  display: table-cell;
  vertical-align: middle;
  text-align: center;
}
.child {
  display: inline-block;
}

栗子

多列布局

1.一列定宽 + 一列自适应

图片描述

<div class="parent">
  <div class="left"><p>left</p></div>
  <div class="right">
    <p>right</p>
    <p>right</p>
  </div>
</div>

方法1:float + margin

.left {float: left; width: 100px;}
.right { margin-left: 120px;} //有20px是间距

方法2:(对方法一的改进)float + margin + (fix)

因为方法1在低版本浏览器有兼容性问题,所以改进一下。

// 首先在right外面加了right-fix这个div
<div class="parent">
  <div class="left"><p>left</p></div>
  <div class="right-fix"> 
    <div class="right">
      <p>right</p>
      <p>right</p>
    </div>
  </div>
</div>

CSS改动:

STEP1:

// .left 和 .right 设置暂时不变
.right-fix {float: right; width: 100%;}

效果为:(注意:我们把right-fix设置为白色背景,只是为了方便观察。)

图片描述

STEP2:

可以看到,由于right-fix宽度为100%,所以跑到了left下面一行。想要回到同一行,需要给right-fix设置一个负的margin-left值-100px。

.right-fix { margin-left: -100px; }

关于为什么设置了margin-left: 100px;就可以使得回到同一行呢?是因为设置了负的margin-left值之后,浏览器计算right-fix元素的宽度后,会加上-100px,也就是减掉100px,这也就是left的宽度,所以left 与 right-fix 加起来没有超过整行的宽度。
想要进一步了解负的margin值可以参考这篇文章:CSS布局奇淫巧计之-强大的负边距

效果如图:

图片描述

STEP3:

不幸的是,因为html文档中right-fix处于left后面,所以left被right-fix遮住了,实际应用中right-fix虽然没有背景色,但是我们还是不会希望它覆盖在left上面。

所以,我们需要提高 left 的层级。如何提高呢?由于设置了position: relative;的元素层级要高于普通元素,所以加上这样一条:

.left{ position: relative; }

具体可以参考张鑫旭写的一篇讲解position:relative;很详细的文章:CSS 相对/绝对(relative/absolute)定位系列(四)

最终达到我们要的效果:

图片描述

到jsfiddle中自己试试去

方法3:float + overflow

.left{
  width: 100px;
  margin-right: 20px;
}
.right {
  overflow: hidden;
}

原理是:设置了overflow:hidden; 之后,会触发BFC模式,而BFC模式内部的布局不受外部影响,所以不会受浮动影响,不会围绕left而是跑到left右边去了。

方法4:table

.parent{
  display: table;
  width: 100%;
  table-layout: fixed; //加速table渲染,实现了布局优先
}
.left, .right {
  display: table-cell;
}
.left {
  width: 100px;
  padding-right: 20px;//因为table-cell不能设margin,所以设置padding来加间距
}

根据table的特性,left设置了100px后,right就占了剩余宽度。

方法5:flex

.parent{ display: flex; }
.left{ width: 100px; margin-right: 20px; }
.right{ flex: 1; }

So easy.

2.多列定宽 + 一列自适应

再加一列定宽就行啦 o(≧v≦)o

3.不定宽 + 一列自适应

图片描述

不定宽意思是:
1.可以随意更改宽度:比如改为100px,200px,同时不需要更改其他样式也可以做到两列自适应布局。
2.或不设置宽度而是由里面子元素的宽度决定。

以下方法对应 [一列定宽+一列自适应] 中的方法

方法1: float + margin ?

不好意思,做不到。

方法2: float + margin +(fix) ?

不好意思,也做不到。

方法3: float + overflow ?

阔以!right的样式没有依赖于width的宽度。代码量也少,很棒棒哦!

方法4:table

阔以!right的样式没有依赖于width的宽度,即不关心width的宽度。

方法5:flex

强大的flex当然可以~(傲娇脸 )

4.两列不定宽 + 一列自适应

没错,跟你想的一样,加一列不定宽的就行了,样式都一样 ㄟ( ▔, ▔ )ㄏ

5.等分布局

图片描述

C + G = 4*(W + G)
以下例子假设间距G = 20px

结构:

<div class="parent">
  <div class="column"><p>1</p></div>
  <div class="column"><p>2</p></div>
  <div class="column"><p>3</p></div>
  <div class="column"><p>4</p></div>
</div>

方法1:float

.parent{ margin-left: -20px; }//就是上面公式中等号左边的G
.column{
  float: left;
  width: 25%;
  padding-left: 20px;//这里要注意,因为我们用padding来表示间距,所以如果你是给p元素设置了background-color,会发现没有间距,p标签的width才是上图中的W
  box-sizing: border-box;
}

方法2:table

<div class="parent-fix">
    <div class="parent">
      <div class="column"><p>1</p></div>
      <div class="column"><p>2</p></div>
      <div class="column"><p>3</p></div>
      <div class="column"><p>4</p></div>
    </div>
</div>
.parent-fix{
  margin-left: -20px;
}
.parent {
  display: table;
  width: 100%;
}
.column {
  display: table-cell;
  padding-left: 20px;//因为单元格不能设置margin,所以间距只能用padding来做。
}

因为table的width默认是随内容宽度变化的,所以需要手动设置width: 100%;。又因为明确设置了宽度的元素就没办法用将margin设为负值的方式增加20px宽度了,所以需要在外面加一个父元素parent-fix
这里大家可以自己试试比较一下给parent-fix设置width为100%不设置width时parent-fix实际宽度(用调试工具里的查看元素看)的区别来理解。

呐,jsfiddle示例在这

方法3:flex

.parent { display: flex; }
.column { flex: 1; } 
.column + .column { margin-left: 20px; }//好用的兄弟选择器 (。・`ω´・)

6.一列定宽+一列自适应(当其中较高的一列高度变化,另一列同步变化)

右侧变高,左侧高度随之变化:

右侧变高,左侧高度随之变化1

↓↓

右侧变高,左侧高度随之变化2

方法1:table

table的列之间有天然等高的特性。

就是上面 1.一列定宽 + 一列自适应中的方法4:table

方法2:flex

flex也是天然的等高 <( ̄︶ ̄)> 因为它默认的align-items为stretch,即在交叉轴上默认拉伸占满整个容器。

仍旧是上面1.一列定宽 + 一列自适应中的方法5:flex

简单到不好意思给栗子

方法3:float

仍旧是参照上面1.一列定宽 + 一列自适应中的方法3:float + overflow,float并没有天然等高,所以要在这个基础上做改动。

.left{
  width: 100px;
  margin-right: 20px;
}
.right {
  overflow: hidden;
}
//增加部分
.left, .right{
  padding-bottom: 9999px;//使得有背景色的部分变的很高
  margin-bottom: -9999px;//用负的margin抵消掉很高的padding,让高度变回left和right中较高的那部分的内容高度,以便parent用overflow: hidden;去隐藏掉超出部分
}
.parent {
  overflow: hidden;//隐藏掉超出边界的部分 
}

其实left的实际高度并没有变,是一种伪等高,只是背景变高。

栗子

7.全等四宫格

图片描述

这是练习题,置几试试吧。

<div class="parent">
  <div class="outer">
    <div class="column">1</div>
    <div class="column">2</div>
  </div>
  <div class="outer">
    <div class="column">3</div>
    <div class="column">4</div>
  </div>
</div>

方法1:flex

.parent {
  display: flex;
  flex-wrap: wrap;
  align-content: space-between;
}
.outer {
  flex-basis: 100%;
  display: flex;
  justify-content: space-between;
}

一颗仅供参考的栗子

方法2:float

我的栗子

方法3:table

一个栗子不一定对

全屏布局

1.定宽(px)+自适应

图片描述

只有主内容区 right 随内容滚动。

方法1.position

<div class="parent">
<div class="top">top</div>
<div class="left">left</div>
<div class="right"><div class="help-right">right</div></div>
<div class="bottom">bottom</div>
</div>
html, body, .parent {height: 100%; overflow: hidden;}//为了让整个页面不滚动
.top {
  position: absolute;
  top: 0; 
  left: 0; right: 0; //注意这个很棒的设置!可以自动占满整行 ヾ(o◕∀◕)ノ 
  height: 100px;
}
.left {
  position: absolute;
  left: 0;
  top: 100px; bottom: 50px;
  width:200px;
}
.right {
  position: absolute;
  left: 200px; right: 0;
  top: 100px; bottom: 50px; //这也是上下占满除了top和bottom之外的所有高度
  overflow: auto;//让主内容区可以滚动
}
.help-right {//假装有很多内容
  width: 1000px;
  height: 1000px;
}
.bottom{
  position: absolute;
  bottom: 0; 
  left: 0; right: 0;
  height: 50px;
}

动手写写才记得住

方法2.flex

<div class="parent">
<div class="top">top</div>
<div class="middle">
<div class="left">left</div>
<div class="right"><div class="help-right">right</div></div>
</div>
<div class="bottom">bottom</div>
</div>
html, body, .parent {height: 100%; overflow: hidden;}
.parent {display: flex; flex-direction: column;}
.top { height: 100px; }
.middle {flex: 1; display: flex;}
.left { width:200px; }
.right { flex: 1; overflow: auto; }
.help-right { width: 1000px; height: 1000px; }
.bottom{ height: 50px; }

栗子

2.百分比定宽(%)+自适应

方法1.position , 方法2.flex :

把原来的用px写的定宽改成百分比就可以了。是相对于body的高度和宽度来变化的。感觉top和bottom高度设置百分比不是很实用。

3.自适应+自适应

图片描述

方法1.position

定宽的高度和宽度影响旁边栏的布局,所以实现不了 - 。-

方法2.flex

阔以实现,而且相当简单 ╮(╯▽╰)╭ 把刚刚设置了高度和宽度的地方去掉就可以了 ∑(っ °Д °;)っ

惊人的栗子

方法3.Grid

阔以实现,但是因为还是W3C的草案,所以会经常变化,不稳定,而且浏览器支持也不好。

响应式

想要达到的效果

只写一个网站,在多个终端显示,在小屏幕上会隐藏部分元素。

现在的情况

在PC端浏览器中可以正常访问的网站,到了手机上之后,内容就会变得特别小。
原因:所有的移动设备都有一个viewport(视窗),这个视窗不是手机屏幕大小,而是一个虚拟的窗口,比如iPhone4的viewport宽度为980px(如下图所示)。显示的时候再按照比例将这980px的内容压缩显示到实际的屏幕宽度中。

图片描述

所以为防止让页面缩小,在移动设备中,我们会做如下设置

<meta name="viewport" content="
 width=device-width //让宽度等于设备宽度,因为不同的移动设备宽度不同 iphone4为320px
 ,initial-scale=1.0 //初始缩放1.0, 即不缩放,网站就不会被缩小了
 ,user-scalable=no //防止用户手动缩放
">

设置结束之后,如何具体开发?

方法1.宽度尽量自适应,而不要用定宽。

方法2.用媒体查询 @media

@media screen and (max-width: 320px) {
  //最大宽度为320px,即视窗宽度小于等于320px
  div{..}
  .class-name{...}
}

@media screen and (min-width: 320px) and (max-width: 769px){
  //最小宽度为320px,最大宽度为769px,即视窗宽度大于320px,小于769px
}

页面优化

目的

减少卡顿
利于SEO
便于代码维护

方法

1. 减少页面请求

减少css文件请求

(1)多个css文件合并成一个
(2)少量css样式内联
(3)避免用import的方式引入css文件,因为每个import语句都会产生一个css请求,并且是同步的请求。

2.减少资源文件大小

(1)减少图片大小
选择合适的图片格式,小尺寸、半透明的用png,大尺寸、色彩绚丽用jpg(因为jpg会对图片进行压缩)
压缩图片

(2)css值缩写
margin,padding,border,font,border-radius等属性

(3)省略值为0 的单位

margin: 0 10px;
line-height: .5;
background-position: 50% 0;

(4)颜色值最短表示

red
rgb(0,0,0)
rgba(0,0,0,0)
#000000
#000

(5)css选择器合并

.left, .right {...}

(6)文件压缩
用工具对文件进行自动压缩,去掉空格。

3.提升页面性能

加载顺序

css通常放在head中,而js通常放在body底部,因为js会阻碍其他资源加载。

减少标签数量。

选择器长度

body .menu ul li a { ... } //太长了
.menu a { ... } //更好

避免耗性能属性

比如:

expression
filter
border-radius
box-shadow
gradients

给图片设置固定宽高,并且图片实际宽高与设置宽高相同,否则浏览器会回流设置多次宽高

所有表现用css实现

4.通过规范提高代码可读性,可维护性

(1)规范:缩进,变量名等
(2)语义化:除了标签,css、id名最好也尽量有意义
(3)尽量避免Hack,一定要用也要统一的标识,比如IE7用*
(4)模块化:相关联的结构做成一个个模块,复用性更强
(5)添加注释

规范与模块化

规范

1.注释的文字两侧需加空格,防止因编码问题导致注释失效

2.为避免命名污染,可以给class加前缀,比如:

g- 布局命名
m- 模块命名

3.语义化命名

//结构化命名
top { ... }

//改用语义化命名
nav { ... }

4.属性的书写顺序

图片描述

模块化

什么是模块化

  1. 一系列相关联的结构组成的整体

  2. 带有一定的语义,而非表现

比如,翻页器(或叫分页器paging)、轮播图。

怎么做?

  1. 为模块分类命名(如.m-, .md-)

  2. 以一个主选择器开头(模块根节点)

  3. 使用以主选择器开头的后代选择器(模块子节点)

<div class="m-nav">
  <ul>
    <li class="z-crt"><a>链接</a></li>
    <li><a>链接</a></li>
  </ul>
</div>
//根节点
.m-nav { ... }
//子节点
.m-nav ul{ ... }
.m-nav li{ ... }
.m-nav a{ ... }
.m-nav .z-crt a{ ... }/* 交互状态变化 */

若有一个模块只是比上述模块多了一个按钮,其余部分完全相同,怎么办?

怎样扩展?

为根节点加一个class就好了,这里我们加一个 m-nav-1

<div class="m-nav m-nav-1">
  <ul>
    <li class="z-crt"><a>链接</a></li>
    <li><a>链接</a></li>
  </ul>
  <a class="btn">我是新加的a标签</a>
</div>
//变化的部分在 .m-nav-1 这个新class中写
.m-nav-1 { ... }
.m-nav-1 a{ ... }
.m-nav-1 .btn{ ... }

网易的规范和代码库

规范页:包含了CSS规范、HTML规范和工程师规范

代码库:包含了常用的布局方式、常见模块和元件的实现以及一些bug、技巧等

——————
教是最好的学。

查看原文

於见 收藏了文章 · 2018-03-14

Vue2 模板中的图片地址如何使用 webpack 定义的别名?

webpack 的别名好处大家也都了解, 但是 vue 的模板中, 对图片地址使用别名时总出现问题, 很久时间的时间都没找到解决办法, 一度认为是 webpack 的原因...

alias: {
  'src': path.resolve(__dirname, '../src'),
  'assets': path.resolve(__dirname, '../src/assets'),
  'components': path.resolve(__dirname, '../src/components')
}
<template>
  <img data-original="assets/images/logo.jpg" />
</template>
<script>
import 'assets/css/style.css'
</script>
<style>
.logo {
  background: url(asset/images/bg.jpg)
}
</style>

上面的代码, 你会发现只有引入style.css是成功的, 图片地址和背景图片地址都会解析失败...

经过各种搜索找原因(这时候, 你会发现百度搜索这些技术型的内容, 真是垃圾中的战斗机), 最终还是找到原因了...
vue-html-loader and css-loader translates non-root URLs to relative paths. In order to treat it like a module path, prefix it with ~
就是要在别名前面加一个~

最终代码写成:

alias: {
  'src': path.resolve(__dirname, '../src'),
  'assets': path.resolve(__dirname, '../src/assets'),
  'components': path.resolve(__dirname, '../src/components')
}
<template>
    <img data-original="~assets/images/logo.jpg" />
</template>
<script>
import 'assets/css/style.css'
</script>
<style>
.logo {
    background: url(~asset/images/bg.jpg)
}
</style>

意思就是: 告诉加载器它是一个模块,而不是相对路径
注意: 只有在template中的静态文件地址和style中的静态文件地址需要加~, 在script里的, 别名定义成什么就写什么.
简单吧, 然而没找到原因前, 你压根就没办法...
到此, 纠结了几个月时间的问题, 终于解决了...

查看原文

於见 收藏了文章 · 2018-02-27

50道CSS基础面试题(附答案)

1 介绍一下标准的CSS的盒子模型?与低版本IE的盒子模型有什么不同的?

标准盒子模型:宽度=内容的宽度(content)+ border + padding + margin
低版本IE盒子模型:宽度=内容宽度(content+border+padding)+ margin

2 box-sizing属性?

用来控制元素的盒子模型的解析模式,默认为content-box
context-box:W3C的标准盒子模型,设置元素的 height/width 属性指的是content部分的高/宽
border-box:IE传统盒子模型。设置元素的height/width属性指的是border + padding + content部分的高/宽

3 CSS选择器有哪些?哪些属性可以继承?

CSS选择符:id选择器(#myid)、类选择器(.myclassname)、标签选择器(div, h1, p)、相邻选择器(h1 + p)、子选择器(ul > li)、后代选择器(li a)、通配符选择器(*)、属性选择器(a[rel="external"])、伪类选择器(a:hover, li:nth-child)

可继承的属性:font-size, font-family, color

不可继承的样式:border, padding, margin, width, height

优先级(就近原则):!important > [ id > class > tag ]
!important 比内联优先级高

4 CSS优先级算法如何计算?

元素选择符: 1
class选择符: 10
id选择符:100
元素标签:1000

  1. !important声明的样式优先级最高,如果冲突再进行计算。
  2. 如果优先级相同,则选择最后出现的样式。
  3. 继承得到的样式的优先级最低。

5 CSS3新增伪类有那些?

p:first-of-type 选择属于其父元素的首个元素
p:last-of-type 选择属于其父元素的最后元素
p:only-of-type 选择属于其父元素唯一的元素
p:only-child 选择属于其父元素的唯一子元素
p:nth-child(2) 选择属于其父元素的第二个子元素
:enabled :disabled 表单控件的禁用状态。
:checked 单选框或复选框被选中。

6 如何居中div?如何居中一个浮动元素?如何让绝对定位的div居中?

div:

border: 1px solid red;
margin: 0 auto; 
height: 50px;
width: 80px;

浮动元素的上下左右居中:

border: 1px solid red;
float: left;
position: absolute;
width: 200px;
height: 100px;
left: 50%;
top: 50%;
margin: -50px 0 0 -100px; 

绝对定位的左右居中:

border: 1px solid black;
position: absolute;
width: 200px;
height: 100px;
margin: 0 auto;
left: 0;
right: 0; 

还有更加优雅的居中方式就是用flexbox,我以后会做整理。

7 display有哪些值?说明他们的作用?

inline(默认)--内联
none--隐藏
block--块显示
table--表格显示
list-item--项目列表
inline-block

8 position的值?

static(默认):按照正常文档流进行排列;
relative(相对定位):不脱离文档流,参考自身静态位置通过 top, bottom, left, right 定位;
absolute(绝对定位):参考距其最近一个不为static的父级元素通过top, bottom, left, right 定位;
fixed(固定定位):所固定的参照对像是可视窗口。

9 CSS3有哪些新特性?

  1. RGBA和透明度
  2. background-image background-origin(content-box/padding-box/border-box) background-size background-repeat
  3. word-wrap(对长的不可分割单词换行)word-wrap:break-word
  4. 文字阴影:text-shadow: 5px 5px 5px #FF0000;(水平阴影,垂直阴影,模糊距离,阴影颜色)
  5. font-face属性:定义自己的字体
  6. 圆角(边框半径):border-radius 属性用于创建圆角
  7. 边框图片:border-image: url(border.png) 30 30 round
  8. 盒阴影:box-shadow: 10px 10px 5px #888888
  9. 媒体查询:定义两套css,当浏览器的尺寸变化时会采用不同的属性

10 请解释一下CSS3的flexbox(弹性盒布局模型),以及适用场景?

该布局模型的目的是提供一种更加高效的方式来对容器中的条目进行布局、对齐和分配空间。在传统的布局方式中,block 布局是把块在垂直方向从上到下依次排列的;而 inline 布局则是在水平方向来排列。弹性盒布局并没有这样内在的方向限制,可以由开发人员自由操作。
试用场景:弹性布局适合于移动前端开发,在Android和ios上也完美支持。

11 用纯CSS创建一个三角形的原理是什么?

首先,需要把元素的宽度、高度设为0。然后设置边框样式。

width: 0;
height: 0;
border-top: 40px solid transparent;
border-left: 40px solid transparent;
border-right: 40px solid transparent;
border-bottom: 40px solid #ff0000;

12 一个满屏品字布局如何设计?

第一种真正的品字:

  1. 三块高宽是确定的;
  2. 上面那块用margin: 0 auto;居中;
  3. 下面两块用float或者inline-block不换行;
  4. 用margin调整位置使他们居中。

第二种全屏的品字布局:
上面的div设置成100%,下面的div分别宽50%,然后使用float或者inline使其不换行。

13 常见的兼容性问题?

  1. 不同浏览器的标签默认的margin和padding不一样。

    *{margin:0;padding:0;}

  2. IE6双边距bug:块属性标签float后,又有横行的margin情况下,在IE6显示margin比设置的大。hack:display:inline;将其转化为行内属性。
  3. 渐进识别的方式,从总体中逐渐排除局部。首先,巧妙的使用“9”这一标记,将IE浏览器从所有情况中分离出来。接着,再次使用“+”将IE8和IE7、IE6分离开来,这样IE8已经独立识别。

    {
    background-color:#f1ee18;/*所有识别*/
    .background-color:#00deff\9; /*IE6、7、8识别*/
    +background-color:#a200ff;/*IE6、7识别*/
    _background-color:#1e0bd1;/*IE6识别*/
    }
    
  4. 设置较小高度标签(一般小于10px),在IE6,IE7中高度超出自己设置高度。hack:给超出高度的标签设置overflow:hidden;或者设置行高line-height 小于你设置的高度。
  5. IE下,可以使用获取常规属性的方法来获取自定义属性,也可以使用getAttribute()获取自定义属性;Firefox下,只能使用getAttribute()获取自定义属性。解决方法:统一通过getAttribute()获取自定义属性。
  6. Chrome 中文界面下默认会将小于 12px 的文本强制按照 12px 显示,可通过加入 CSS 属性 -webkit-text-size-adjust: none; 解决。
  7. 超链接访问过后hover样式就不出现了,被点击访问过的超链接样式不再具有hover和active了。解决方法是改变CSS属性的排列顺序:L-V-H-A ( love hate ): a:link {} a:visited {} a:hover {} a:active {}

14 为什么要初始化CSS样式

因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对CSS初始化往往会出现浏览器之间的页面显示差异。

15 absolute的containing block计算方式跟正常流有什么不同?

无论属于哪种,都要先找到其祖先元素中最近的 position 值不为 static 的元素,然后再判断:

  1. 若此元素为 inline 元素,则 containing block 为能够包含这个元素生成的第一个和最后一个 inline box 的 padding box (除 margin, border 外的区域) 的最小矩形;
  2. 否则,则由这个祖先元素的 padding box 构成。

如果都找不到,则为 initial containing block。

补充:

  1. static(默认的)/relative:简单说就是它的父元素的内容框(即去掉padding的部分)
  2. absolute: 向上找最近的定位为absolute/relative的元素
  3. fixed: 它的containing block一律为根元素(html/body)

16 CSS里的visibility属性有个collapse属性值?在不同浏览器下以后什么区别?

当一个元素的visibility属性被设置成collapse值后,对于一般的元素,它的表现跟hidden是一样的。

  1. chrome中,使用collapse值和使用hidden没有区别。
  2. firefox,opera和IE,使用collapse值和使用display:none没有什么区别。

17 display:none与visibility:hidden的区别?

display:none 不显示对应的元素,在文档布局中不再分配空间(回流+重绘)
visibility:hidden 隐藏对应元素,在文档布局中仍保留原来的空间(重绘)

18 position跟display、overflow、float这些特性相互叠加后会怎么样?

display属性规定元素应该生成的框的类型;position属性规定元素的定位类型;float属性是一种布局方式,定义元素在哪个方向浮动。
类似于优先级机制:position:absolute/fixed优先级最高,有他们在时,float不起作用,display值需要调整。float 或者absolute定位的元素,只能是块元素或表格。

19 对BFC规范(块级格式化上下文:block formatting context)的理解?

BFC规定了内部的Block Box如何布局。
定位方案:

  1. 内部的Box会在垂直方向上一个接一个放置。
  2. Box垂直方向的距离由margin决定,属于同一个BFC的两个相邻Box的margin会发生重叠。
  3. 每个元素的margin box 的左边,与包含块border box的左边相接触。
  4. BFC的区域不会与float box重叠。
  5. BFC是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。
  6. 计算BFC的高度时,浮动元素也会参与计算。

满足下列条件之一就可触发BFC

  1. 根元素,即html
  2. float的值不为none(默认)
  3. overflow的值不为visible(默认)
  4. display的值为inline-block、table-cell、table-caption
  5. position的值为absolute或fixed

20 为什么会出现浮动和什么时候需要清除浮动?清除浮动的方式?

浮动元素碰到包含它的边框或者浮动元素的边框停留。由于浮动元素不在文档流中,所以文档流的块框表现得就像浮动框不存在一样。浮动元素会漂浮在文档流的块框上。
浮动带来的问题:

  1. 父元素的高度无法被撑开,影响与父元素同级的元素
  2. 与浮动元素同级的非浮动元素(内联元素)会跟随其后
  3. 若非第一个元素浮动,则该元素之前的元素也需要浮动,否则会影响页面显示的结构。

清除浮动的方式:

  1. 父级div定义height
  2. 最后一个浮动元素后加空div标签 并添加样式clear:both。
  3. 包含浮动元素的父标签添加样式overflow为hidden或auto。
  4. 父级div定义zoom

21 上下margin重合的问题

在重合元素外包裹一层容器,并触发该容器生成一个BFC。
例子:

<div class="aside"></div>
<div class="text">
    <div class="main"></div>
</div>
<!--下面是css代码-->
 .aside {
            margin-bottom: 100px;  
            width: 100px;
            height: 150px;
            background: #f66;
        }
        .main {
            margin-top: 100px;
            height: 200px;
            background: #fcc;
        }
         .text{
            /*盒子main的外面包一个div,通过改变此div的属性使两个盒子分属于两个不同的BFC,以此来阻止margin重叠*/
            overflow: hidden;  //此时已经触发了BFC属性。
        }

22设置元素浮动后,该元素的display值是多少?

自动变成display:block

23 移动端的布局用过媒体查询吗?

通过媒体查询可以为不同大小和尺寸的媒体定义不同的css,适应相应的设备的显示。

  1. <head>里边

    <link rel="stylesheet" type="text/css" href="xxx.css" media="only screen and (max-device-width:480px)">

  2. CSS : @media only screen and (max-device-width:480px) {/css样式/}

24 使用 CSS 预处理器吗?
Less sass

25 CSS优化、提高性能的方法有哪些?

  1. 避免过度约束
  2. 避免后代选择符
  3. 避免链式选择符
  4. 使用紧凑的语法
  5. 避免不必要的命名空间
  6. 避免不必要的重复
  7. 最好使用表示语义的名字。一个好的类名应该是描述他是什么而不是像什么
  8. 避免!important,可以选择其他选择器
  9. 尽可能的精简规则,你可以合并不同类里的重复规则

26 浏览器是怎样解析CSS选择器的?

CSS选择器的解析是从右向左解析的。若从左向右的匹配,发现不符合规则,需要进行回溯,会损失很多性能。若从右向左匹配,先找到所有的最右节点,对于每一个节点,向上寻找其父节点直到找到根元素或满足条件的匹配规则,则结束这个分支的遍历。两种匹配规则的性能差别很大,是因为从右向左的匹配在第一步就筛选掉了大量的不符合条件的最右节点(叶子节点),而从左向右的匹配规则的性能都浪费在了失败的查找上面。
而在 CSS 解析完毕后,需要将解析的结果与 DOM Tree 的内容一起进行分析建立一棵 Render Tree,最终用来进行绘图。在建立 Render Tree 时(WebKit 中的「Attachment」过程),浏览器就要为每个 DOM Tree 中的元素根据 CSS 的解析结果(Style Rules)来确定生成怎样的 Render Tree。

27 在网页中的应该使用奇数还是偶数的字体?为什么呢?

使用偶数字体。偶数字号相对更容易和 web 设计的其他部分构成比例关系。Windows 自带的点阵宋体(中易宋体)从 Vista 开始只提供 12、14、16 px 这三个大小的点阵,而 13、15、17 px时用的是小一号的点。(即每个字占的空间大了 1 px,但点阵没变),于是略显稀疏。

28 margin和padding分别适合什么场景使用?

何时使用margin:

  1. 需要在border外侧添加空白
  2. 空白处不需要背景色
  3. 上下相连的两个盒子之间的空白,需要相互抵消时。

何时使用padding:

  1. 需要在border内侧添加空白
  2. 空白处需要背景颜色
  3. 上下相连的两个盒子的空白,希望为两者之和。

兼容性的问题:在IE5 IE6中,为float的盒子指定margin时,左侧的margin可能会变成两倍的宽度。通过改变padding或者指定盒子的display:inline解决。

29 元素竖向的百分比设定是相对于容器的高度吗?

当按百分比设定一个元素的宽度时,它是相对于父容器的宽度计算的,但是,对于一些表示竖向距离的属性,例如 padding-top , padding-bottom , margin-top , margin-bottom 等,当按百分比设定它们时,依据的也是父容器的宽度,而不是高度。

30 全屏滚动的原理是什么?用到了CSS的哪些属性?

  1. 原理:有点类似于轮播,整体的元素一直排列下去,假设有5个需要展示的全屏页面,那么高度是500%,只是展示100%,剩下的可以通过transform进行y轴定位,也可以通过margin-top实现
  2. overflow:hidden;transition:all 1000ms ease;

31 什么是响应式设计?响应式设计的基本原理是什么?如何兼容低版本的IE?

响应式网站设计(Responsive Web design)是一个网站能够兼容多个终端,而不是为每一个终端做一个特定的版本。
基本原理是通过媒体查询检测不同的设备屏幕尺寸做处理。
页面头部必须有meta声明的viewport。

<meta name=’viewport’ content=”width=device-width, initial-scale=1. maximum-scale=1,user-scalable=no”>

32 视差滚动效果?

视差滚动(Parallax Scrolling)通过在网页向下滚动的时候,控制背景的移动速度比前景的移动速度慢来创建出令人惊叹的3D效果。

  1. CSS3实现
    优点:开发时间短、性能和开发效率比较好,缺点是不能兼容到低版本的浏览器
  2. jQuery实现
    通过控制不同层滚动速度,计算每一层的时间,控制滚动效果。
    优点:能兼容到各个版本的,效果可控性好
    缺点:开发起来对制作者要求高
  3. 插件实现方式
    例如:parallax-scrolling,兼容性十分好

33 ::before 和 :after中双冒号和单冒号有什么区别?解释一下这2个伪元素的作用

  1. 单冒号(:)用于CSS3伪类,双冒号(::)用于CSS3伪元素。
  2. ::before就是以一个子元素的存在,定义在元素主体内容之前的一个伪元素。并不存在于dom之中,只存在在页面之中。

:before 和 :after 这两个伪元素,是在CSS2.1里新出现的。起初,伪元素的前缀使用的是单冒号语法,但随着Web的进化,在CSS3的规范里,伪元素的语法被修改成使用双冒号,成为::before ::after

34 你对line-height是如何理解的?

行高是指一行文字的高度,具体说是两行文字间基线的距离。CSS中起高度作用的是height和line-height,没有定义height属性,最终其表现作用一定是line-height。
单行文本垂直居中:把line-height值设置为height一样大小的值可以实现单行文字的垂直居中,其实也可以把height删除。
多行文本垂直居中:需要设置display属性为inline-block。

35 怎么让Chrome支持小于12px 的文字?

p{font-size:10px;-webkit-transform:scale(0.8);} //0.8是缩放比例

36 让页面里的字体变清晰,变细用CSS怎么做?

-webkit-font-smoothing在window系统下没有起作用,但是在IOS设备上起作用-webkit-font-smoothing:antialiased是最佳的,灰度平滑。

37 position:fixed;在android下无效怎么处理?

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"/>

38 如果需要手动写动画,你认为最小时间间隔是多久,为什么?
多数显示器默认频率是60Hz,即1秒刷新60次,所以理论上最小间隔为1/60*1000ms = 16.7ms。

39 li与li之间有看不见的空白间隔是什么原因引起的?有什么解决办法?

行框的排列会受到中间空白(回车空格)等的影响,因为空格也属于字符,这些空白也会被应用样式,占据空间,所以会有间隔,把字符大小设为0,就没有空格了。
解决方法:

  1. 可以将<li>代码全部写在一排
  2. 浮动li中float:left
  3. 在ul中用font-size:0(谷歌不支持);可以使用letter-space:-3px

40 display:inline-block 什么时候会显示间隙?

  1. 有空格时候会有间隙 解决:移除空格
  2. margin正值的时候 解决:margin使用负值
  3. 使用font-size时候 解决:font-size:0、letter-spacing、word-spacing

41 有一个高度自适应的div,里面有两个div,一个高度100px,希望另一个填满剩下的高度

外层div使用position:relative;高度要求自适应的div使用position: absolute; top: 100px; bottom: 0; left: 0

42 png、jpg、gif 这些图片格式解释一下,分别什么时候用。有没有了解过webp?

  1. png是便携式网络图片(Portable Network Graphics)是一种无损数据压缩位图文件格式.优点是:压缩比高,色彩好。 大多数地方都可以用。
  2. jpg是一种针对相片使用的一种失真压缩方法,是一种破坏性的压缩,在色调及颜色平滑变化做的不错。在www上,被用来储存和传输照片的格式。
  3. gif是一种位图文件格式,以8位色重现真色彩的图像。可以实现动画效果.
  4. webp格式是谷歌在2010年推出的图片格式,压缩率只有jpg的2/3,大小比png小了45%。缺点是压缩的时间更久了,兼容性不好,目前谷歌和opera支持。

43 style标签写在body后与body前有什么区别?

页面加载自上而下 当然是先加载样式。
写在body标签后由于浏览器以逐行方式对HTML文档进行解析,当解析到写在尾部的样式表(外联或写在style标签)会导致浏览器停止之前的渲染,等待加载且解析样式表完成之后重新渲染,在windows的IE下可能会出现FOUC现象(即样式失效导致的页面闪烁问题)

44 CSS属性overflow属性定义溢出元素内容区的内容会如何处理?

参数是scroll时候,必会出现滚动条。
参数是auto时候,子元素内容大于父元素时出现滚动条。
参数是visible时候,溢出的内容出现在父元素之外。
参数是hidden时候,溢出隐藏。

45 阐述一下CSS Sprites

将一个页面涉及到的所有图片都包含到一张大图中去,然后利用CSS的 background-image,background- repeat,background-position 的组合进行背景定位。利用CSS Sprites能很好地减少网页的http请求,从而大大的提高页面的性能;CSS Sprites能减少图片的字节。

持续更新中...

查看原文

於见 关注了用户 · 2017-02-17

题叶 @jiyinyiyong

ClojureScript 爱好者.

关注 1961

於见 赞了文章 · 2017-01-19

如何打造一个令人愉悦的前端开发环境(三)

往期回顾

前面2期都讲得是浏览器端的东西比较多,包括Webpack,虽然是Node处理的,但是还是浏览器端用的多,对于现在的前端开发来说,不懂一点服务端的东西,简直没办法活,一般的招聘要求都会加上要懂一门服务端的语言,例如:PHP,Java之类的啦。如图所示:

知乎的招聘

所以我们这期就讲Node的东西。

程咬金的三板斧

一、劈脑袋 -- 工具链

Node在前端领域使用最为广泛的就是工具链了,一期提到的构建工具都是Node写的,当然还有其他很多工具,比如:京东工程化百度开源构建工具FIS3微信发布的工作流工具等等一系列前端工具都是用Node写的。广泛的说,我认为一期提到的编辑器也算工具链的中的一种,Atom,vs code,Brackets都和Node密不可分。我个人感觉,Node的发展,实际上大大解放了前端的生产力,对于其他的服务端语言的依赖基本可以说降到最低,可以依据自己的需要编写工具来完成技术目标。

这方面大家也可以自己来产出下,例如我自己写了个小工具供自己使用:
vuejs 格式化 Atom插件
现在下载量也不错,有2000多了,还有好几个issues没有处理,哭!!

二、鬼剔牙 -- 中间层

对于很多FE来说,要搭建一个后端环境很是麻烦,而且不熟悉,容易出错(java,ruby,php),最糟的是自己不懂,出错了完全不会调试,你的表情此时是这样的:

懵逼

那么在13、14年的时候,淘宝的前端团队,开始连续发文,前后端分离的思考和实践系列文章,提到了中途岛计划,也就是把Node作为前端和服务端的中间层,也就是这个架构,

网站架构

从这种图,不难看出,Node取代原来php,java干的一部分事情,也就是我们常说的MVC框架中的VC基本都给Node来干,FE干的事情更多了,能掌握的东西多了,意味着对于自己更加灵活,可以考虑更多的组件化,工程化,性能监控,数据分析的事情。

这方面的实践大家可以参考美团这边的图文:

美团酒店

美团酒店Node全栈开发实践

三、掏耳朵 -- 火热的全栈

Full Stack developer 是近年来热炒的一个概念,究其原因,跟Node的火热不无关系,早些年讲,一个人(大牛不算普通人)既要精通java又要精通js,html,css还是很困难,很多思维都不太一样,分开也很正常,而Node的出现,为很多比较厉害的前端提供了切入到服务端的机会,语言层面的问题不在是难点,重要的对服务端的知识点的熟悉程度。Node的最后一个大招就是替换一些传统的服务端语言,例如php,ruby,java等,在业务层上面使用Node来开发服务端完全不成问题。

例如: uber的调度系统几乎都是用 node.js 编写的

这方面的文章也有很多了,大家可以自己去搜搜看,包括各种框架,还有各种开源系统,都可以找到。当然也还有各种各样的坑和问题以待大家去踩和解决。

说说自家事

我们公司来说的话,三板斧基本都用上了,打包构建自不用谈,基本每个前端都会用到,第二板斧我们公司已经基本切换过来了,年后3月启动,目前是所有的web页面都是Node作为中间层,替换了php的渲染,中间自然有很多的困难要克服,但整体上来说开发的效率还是大大提升,不需要在配置php的环境,也不用在关心各种环境的依赖,整体上自己的一个独立的服务,使用接口的形式和服务端通信。

那么三板斧为何会用到,主要是目前国内最常见的mobile的web页面,基本在微信里面流传,然后这些页面还需要一定的数据交互,而且这种页面的特点就是短平快,不需要那么严谨,这种页面特别适合前端自己一撸到底,前后端通吃,接上 MongoDB当做数据库,基本两三天之内就能开发一个活动页面出来,不需要对其他服务有任何依赖,包括微信授权都可以自己搞定,工作量其实比对接其他语言服务大不了多少,某些方面,我个人认为还减少了很多的沟通成本。

痛点-- 造就了自己的一个开源

express的路由插件

先说说这个插件做什么的: 主要是自动的加载express框架下面的路由,免得一个一个路由需要手写。

通常我们在express框架下面,写路由的时候都是一个一个的手写,然后在app.js里面去一个一个引用,一般是这样子的

手写路由

那么好一点的情况,是这样子的,分散每一个相同名字的路由到文件中,然后引用文件在app.js里面。

代码少了不少

但实际上你可能在项目中路由情况是这样子的

路由列表

你有什么想法?

图片描述

虽然这样子也就是一个文件多两行代码,我还是不爽,我为什么要因为同一个规则而去多写这两个代码,而且10个两行,就是20行,原则上,能用机器干的事情,就不人干,而且PHP的一些MVC框架可以自动加载路由,他们会有一个文件夹的分层,很明显,路由都放到Controller文件夹下,然后根据路由名来匹配文件名的相应action,依据这个我自己就撸了一个express的自动加载路由,然后考虑了下一些特殊情况,做了点配置,不过目前只是支持一级目录,没有考虑多级目录情况,有需要可以自己添加,或者给我提issues。

照例总结

本篇文章主要讲的是关于Node的东东,它的使用方向,更偏向结合前端的使用,并非是很深入的Node原理,也算是给很多前端解惑下,为什么要使用Node,以及如何使用Node,不要盲目的听信别人的建议,需要结合自己项目情况,技术水平,以及团队配比。

更多的Node的使用细节和技巧建议关注:

美团博客

大搜车

cnode论坛

下一篇我们开启如何结合Webpack和express 搭建一个开发环境和项目目录

查看原文

赞 8 收藏 64 评论 2

於见 赞了文章 · 2016-09-19

WebPack1.x 常用功能介绍

注意:本文描述的配置只适用webpack1.x;由于webpack已经推出2.x并有大量更改,特此申明

概述

Webpack是一款用户打包前端模块的工具。主要是用来打包在浏览器端使用的javascript的。同时也能转换、捆绑、打包其他的静态资源,包括css、image、font file、template等。这里就尽量详细的来介绍下一些基本功能的使用。

安装

npm install webpack -g

运行webpack

webpack需要编写一个config文件,然后根据这个文件来执行需要的打包功能。我们现在来编写一个最简单的config。新建一个文件,命名为webpack-config.js。config文件实际上就是一个Commonjs的模块。内容如下:

var path = require('path');
var buildPath = path.resolve(__dirname,"build");
var nodemodulesPath = path.resolve(__dirname,'node_modules');

var config = {
    //入口文件配置
    entry:path.resolve(__dirname,'src/main.js'),
    resolve:{
        extentions:["","js"]//当requrie的模块找不到时,添加这些后缀
    },
    //文件导出的配置
    output:{
        path:buildPath,
        filename:"app.js"
    }
}

module.exports = config;

我的目录结构是这样的:


webpack
    |---index.html
    |---webpack-config.js
    |---src
         |---main.js
         |---js
              |---a.js

main.js文件内容如下:


var a = require('./js/a');
a();
console.log('hello world');
document.getElementById("container").innerHTML = "<p>hello world</p>";

a.js文件内容如下:

module.exports = function(){
    console.log('it is a ');
}

然后我们执行如下的命令:


webpack --config webpack-config.js --colors

这样我们就能在目录里面看到一个新生成的目录build,目录结构如下:


webpack
    |---index.html
    |---webpack-config.js
    |---build
         |---app.js

然后引用app.js就Ok啦。main.js和模块a.js的内容就都打包到app.js中了。这就演示了一个最简单的把模块的js打包到一个文件的过程了。

介绍webpack config文件

webpack是根据config里面描述的内容对一个项目进行打包的。接着我们来解释下config文件中的节点分别代表什么意思。一个config文件,基本都是由以下几个配置项组成的。

entry

配置要打包的文件的入口;可以配置多个入口文件,下面会有介绍。

resolve

配置文件后缀名(extensions),除了js,还有jsx、coffee等等。
alias配置项,可以为常用模块配置改属性,可以节省编译的搜索时间。例如:

    resolve:{
        extensions:['.js','.jsx'],
        alias:{
            'react':path.join(nodeModulesPath,'react/react.js')
        }
    }

除了这个功能还可以配置其他有用的功能,由于我还不完全了解,有知道的朋友欢迎指教。

output

配置输出文件的路径,文件名等。

module(loaders)

配置要使用的loader。把资源文件(css、图片、html等非js模块)处理成相应的js模块,然后其它的plugins才能对这些资源进行下一步处理。比如babel-loader可以把es6的文件转换成es5。
大部分的对文件的处理的功能都是通过loader实现的。loader可以用来处理在入口文件中require的和其他方式引用进来的文件。loader一般是一个独立的node模块,要单独安装。

loader配置项:

test: /\.(js|jsx)$/,           //注意是正则表达式,不要加引号,匹配要处理的文件
loader: 'eslint-loader',       //要使用的loader,"-loader"可以省略
include: [path.resolve(__dirname, "src/app")],   //把要处理的目录包括进来
exclude: [nodeModulesPath]     //排除不处理的目录

目前已有的loader列表:https://webpack.github.io/docs/list-of-loaders.html

一个module的例子:

module: {
    preLoaders: [
      {
        test: /\.(js|jsx)$/,
        loader: 'eslint-loader',
        include: [path.resolve(__dirname, "src/app")],
        exclude: [nodeModulesPath]
      },
    ],
    loaders: [
      {
        test: /\.(js|jsx)$/, //正则表达式匹配 .js 和 .jsx 文件
        loader: 'babel-loader?optional=runtime&stage=0',//对匹配的文件进行处理的loader 
        exclude: [nodeModulesPath]//排除node module中的文件
      }
    ]
}

plugins

顾名思义,就是配置要使用的插件。plugin是比loader功能更强大的插件,能使用更多的wepack api。来看一个使用plugin的例子:

plugins: [
    //压缩打包的文件
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        //supresses warnings, usually from module minification
        warnings: false
      }
    }),
    //允许错误不打断程序
    new webpack.NoErrorsPlugin(),
    //把指定文件夹xia的文件复制到指定的目录
    new TransferWebpackPlugin([
      {from: 'www'}
    ], path.resolve(__dirname,"src"))
  ]

目前已有的plugins列表:http://webpack.github.io/docs/list-of-plugins.html

如何压缩输出的文件

plugins: [
    //压缩打包的文件
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        //supresses warnings, usually from module minification
        warnings: false
      }
    })]

如何copy目录下的文件到输出目录

copy文件需要通过插件"transfer-webpack-plugin"来完成。

安装:

npm install transfer-webpack-plugin  -save

配置:

var TransferWebpackPlugin = require('transfer-webpack-plugin');
//其他节点省略    
plugins: [
    //把指定文件夹下的文件复制到指定的目录
    new TransferWebpackPlugin([
      {from: 'www'}
    ], path.resolve(__dirname,"src"))
  ]

打包javascript模块

支持的js模块化方案包括:

  • ES6 模块

    import MyModule from './MyModule.js';
  • CommonJS

    var MyModule = require('./MyModule.js');
  • AMD

    define(['./MyModule.js'], function (MyModule) {
    });

上面已经演示了打包js模块,这里不再重复。ES6的模块需要配置babel-loader来先把处理一下js文件。
下面展示下打包ES模块的配置文件:


var webpack = require('webpack');
var path = require('path');
var buildPath = path.resolve(__dirname, 'build');
var nodeModulesPath = path.resolve(__dirname, 'node_modules');
var TransferWebpackPlugin = require('transfer-webpack-plugin');

var config = {
  entry: [path.join(__dirname, 'src/main.js')],
  resolve: {
    extensions: ["", ".js", ".jsx"]
    //node_modules: ["web_modules", "node_modules"]  (Default Settings)
  },
  output: {
    path: buildPath,    
    filename: 'app.js'  
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),
    new webpack.NoErrorsPlugin(),
    new TransferWebpackPlugin([
      {from: 'www'}
    ], path.resolve(__dirname,"src"))
  ],
  module: {
    preLoaders: [
      {
        test: /\.(js|jsx)$/,
        loader: 'eslint-loader',
        include: [path.resolve(__dirname, "src/app")],
        exclude: [nodeModulesPath]
      },
    ],
    loaders: [
      {
        test: /\.js$/, //注意是正则表达式,不要加引号
        loader: 'babel-loader?optional=runtime&stage=0',//babel模块相关的功能请自查,这里不做介绍
        exclude: [nodeModulesPath]
      }
    ]
  },
  //Eslint config
  eslint: {
    configFile: '.eslintrc' //Rules for eslint
  },
};

module.exports = config;

打包静态资源

css/sass/less

安装css-loader和style-loader


npm install css-loader --save -dev
npm install style-loader --save -dev

config配置:


var config = {
    entry:path.resolve(__dirname,'src/main.js'),
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"app.js"
    },
    module:{
        loaders:[{
            test:/\.css$/,
            loader:'style!css',//sass配置:style!css!sass 执行顺序:左<--右
            exclude:nodemodulesPath
        }]
    }
}

style-loader会把css文件嵌入到html的style标签里,css-loader会把css按字符串导出,这两个基本都是组合使用的。打包完成的文件,引用执行后,会发现css的内容都插入到了head里的一个style标签里。
如果是sass或less配置方式与上面类似。

images

可以通过url-loader把较小的图片转换成base64的字符串内嵌在生成的文件里。
安装:


npm install url-loader --save -dev

config配置:

var config = {
    entry:path.resolve(__dirname,'src/main.js'),
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"app.js"
    },
    module:{
        loaders:[{
            test:/\.css$/,
            loader:'style!css',//
            exclude:nodemodulesPath
        },
        { test:/\.png$/,loader:'url-loader?limit=10000'}//限制大小小于10k的
        ]
    }
}

css文件内容:


#container{
    color: #f00;
    background:url(images/logo-201305.png);
    /*生成完图片会被处理成base64的字符串 注意:不要写'/images/logo-201305.png',否则图片不被处理*/
}

iconfont

内嵌iconfont的使用方法其实和上述处理png图片的方法一致。通过url-loader来处理。

config配置:


var config = {
    entry:path.resolve(__dirname,'src/main.js'),
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"app.js"
    },
    module:{
        loaders:[{
            test:/\.css$/,
            loader:'style!css',//
            exclude:nodemodulesPath
        },
        { test:/\.(png|woff|svg|ttf|eot)$/,loader:'url-loader?limit=10000'}//限制大小小于10k的
        ]
    }
}

css文件内容:


@font-face {font-family: 'iconfont';
src: url('fonts/iconfont.eot'); /* IE9*/
src: url('fonts/iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('fonts/iconfont.woff') format('woff'), /* chrome、firefox */
url('fonts/iconfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
url('fonts/iconfont.svg#iconfont') format('svg'); /* iOS 4.1- */
}

执行打包后会把字体文件都转换成base64字符串内容到文件里.
这里有个头疼的问题,就是每个浏览器支持的字体格式不一样,由于把全部格式的字体打包进去,造成不必要的资源浪费。

打包template

我以打包handlebars的模块为例,来演示下打包模块的过程。有的模板对应的loader,有可能没有现成的,恐怕要自己实现loader。

先安装必须的node模块

npm install handlebars-loader --save -dev
npm install handlebars -save//是必须的

config配置:


var config = {
    entry:path.resolve(__dirname,'src/main.js'),
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"app.js"
    },
    module:{
        loaders:[
        { test: /\.html$/, loader: "handlebars-loader" }
        ]
    }
}

新建一个模板文件tb.html,目录结构:

webpack
    |---index.html
    |---webpack-config.js
    |---src
         |---template
         |         |---tb.html
         |---main.js

main.js中调用模块的代码如下:


var template = require("./template/tp.html");
var data={say_hello:"it is handlebars"};
var html = template(data);
document.getElementById('tmpl_container').innerHTML = html;         

公用的模块分开打包

这需要通过插件“CommonsChunkPlugin”来实现。这个插件不需要安装,因为webpack已经把他包含进去了。
接着我们来看配置文件:

var config = {
    entry:{app:path.resolve(__dirname,'src/main.js'),
            vendor: ["./src/js/common"]},//【1】注意这里
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"app.js"
    },
    module:{
        loaders:[{
            test:/\.css$/,
            loader:'style!css',
            exclude:nodemodulesPath
        }
        ]
    },
    plugins:[
        new webpack.optimize.UglifyJsPlugin({
             compress: {
                warnings: false
             }
        }),
        //【2】注意这里  这两个地方市用来配置common.js模块单独打包的
        new webpack.optimize.CommonsChunkPlugin({
            name: "vendor",//和上面配置的入口对应
            filename: "vendor.js"//导出的文件的名称
        })
    ]
}

目录结构现在是这样的:


webpack
  |---index.html
  |---webpack-config.js
  |---src
     |---main.js
     |---js
          |---a.js    //a里面require了common
          |---common.js

执行webpack会生成app.js和common.js两个文件.

code split(模块分离,按需加载)

有些场景,我们可能希望模块在需要的时候再加载,而不是一股脑儿打包到一起。从而加速首屏的加载速度。举个例子,在做单页应用的时候,每个场景对应一个模块。如果场景很多,把模块打包到一起,最后的bundle文件必然很臃肿,加载很慢。那么只要在每个场景需要展示的时候,再加载对应的js模块。就可以优化这个问题了。webpack支持模块按需加载,这个功能叫code split。下面介绍怎么使用这个功能。

目录结构:


webpack
  |---index.html
  |---webpack-config.js
  |---src
     |---main.js
     |---js
          |---codeSplit.js
          

codeSplit.js:


//就是普通的模块 没什么特殊的
console.log('code split');

module.exports = {
    name:'cplll'
}             

main.js:

var cp = function(resolve){
     require.ensure(['./js/codeSplit.js'],function(){//注意这里哦,就是用require.ensure来按需加载的,这是webpack特有的
        resolve(require('./js/codeSplit.js'));//加载好 require模块
    });
}

var getModule = function(){
    return new Promise((resolve,reject)=>{
        cp(resolve);
    });
}

getModule().then((cl)=>{
    console.log(cl.name);
});

config配置:

//...省略
var buildPath = path.resolve(__dirname,"build");
var config = {    
    entry:{
        m1:path.resolve(__dirname,'src/main.js')
    },//注意在这里添加文件的入口
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"app.js",
        publicPath:'build/' //注意这里哦,分离出来的模块会按这个路径来加载
    }    
}

执行命令:

webpack --config webpack-config.js --colors

生成结果:

webpack
  |---index.html
  |---webpack-config.js
  |---build //生成结果
  |    |---app.js
  |    |---1.app.js
  |---src
     |---main.js
     |---js
          |---codeSplit.js

页面里引用

<script type="text/javascript" data-original="./build/app.js"></script>

打开页面就是发现,app.js和1.app.js(在cp函数调用的时候加载)分开加载了。
图片描述

最后需要特别注意,配置output里的publicPath。这里容易有坑。因为不配置加载路径是这样的:

http://localhost:9527/1.app.js

配置以后(publicPath:'build/'):

http://localhost:9527/build/1.app.js

多个入口

config配置:

var config = {    
    entry:{
        m1:path.resolve(__dirname,'src/main.js'),
         m2:path.resolve(__dirname,'src/main1.js')
    },//注意在这里添加文件的入口
    resolve:{
        extentions:["","js"]
    },
    output:{
        path:buildPath,
        filename:"[name].js"//注意这里使用了name变量
    }    
}

webpack-dev-server

在开发的过程中个,我们肯定不希望,每次修改完都手动执行webpack命令来调试程序。所以我们可以用webpack-dev-server这个模块来取代烦人的执行命令。它会监听文件,在文件修改后,自动编译、刷新浏览器的页面。另外,编译的结果是保存在内存中的,而不是实体的文件,所以是看不到的,因为这样会编译的更快。它就想到与一个轻量的express服务器。
安装:


npm install webpack-dev-server --save -dev

config配置:


var config = {
    entry:path.resolve(__dirname,'src/main.js'),
    resolve:{
        extentions:["","js"]
    },
    //Server Configuration options
    devServer:{
        contentBase: '',  //静态资源的目录 相对路径,相对于当前路径 默认为当前config所在的目录
        devtool: 'eval',
        hot: true,        //自动刷新
        inline: true,    
        port: 3005        
    },
    devtool: 'eval',
    output:{
        path:buildPath,
        filename:"app.js"
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),//开启热替换插件
        new webpack.NoErrorsPlugin()
    ]
}

我的目录结构:


webpack
  |---index.html
  |---webpack-config.js//我把静态资源目录配置在了这里
  |---src
     |---main.js
     |---js
          |---a.js
          |---common.js

执行命令:


webpack-dev-server --config webpack-dev-config.js  --inline --colors

默认访问地址:

http://localhost:3000/index.html(根据配置会不一样)

有一点需要声明,在index.html(引用导出结果的html文件)里直接引用“app.js”,不要加父级目录,因为此时app.js在内存里与output配置的目录无关:

<script type="text/javascript" data-original="app.js"></script>

详细文档在这里查看:http://webpack.github.io/docs/webpack-dev-server.html

Hot Module Replacement

热替换是指在应用运行时候替换、添加、移除某个模块而不需要全部模块重新编译、整个页面重新加载。在web应用变的越来越复杂的今天,webpack的编译速度会越来越慢。使用热替换能大大提高webpack的编译速度,提升开发效率。下面介绍如何基于webpack-dev-server配置热替换。

config配置:


var config = {
    entry:[
        'webpack/hot/dev-server',//注意点1:热替换配置点1
        path.resolve(__dirname,'src/main1.js')
    ],
    // entry:{m1:path.resolve(__dirname,'src/main.js'),
    //     m2:path.resolve(__dirname,'src/main1.js')},
    resolve:{
        extentions:["","js"]
    },
    // target: 'node',
    //Server Configuration options
    devServer:{
        contentBase: '',  //Relative directory for base of server
        devtool: 'eval',
        hot: true,        //注意点2:热替换配置点2
        inline: true,
        port: 3005        //Port Number
    },
    devtool: 'eval',
    output:{
        path:buildPath,
        filename:"app.js"
    },
    plugins: [
        //Enables Hot Modules Replacement
        new webpack.HotModuleReplacementPlugin(),//注意点3:热替换配置点3
        //Allows error warnings but does not stop compiling. Will remove when eslint is added
        new webpack.NoErrorsPlugin()
    ],
}

配置文件里添加3个配置点

  1. entry 节点里添加 'webpack/hot/dev-server'

  2. devServer节点里添加 hot: true

  3. plugins 节点里 new webpack.HotModuleReplacementPlugin()

这样配置文件就配置好了。接下来在代码文件里添加热替换要监听的模块。代码如下:

var h1 = require('./hot1');
if(module.hot){//判断是否开启了热替换
    module.hot.accept('./hot1',function(){//在hot1模块更新时,执行替换
        h1 = require('./hot1');
    });
}

更多信息参考:webpack-dev-server和热替换介绍

如何区分开发及生产环境

在webpack.config.js使用process.env.NODE_ENV进行判断
在package.json里面的script设置环境变量,注意mac与windows的设置方式不一样

"scripts": {
    "publish-mac": "export NODE_ENV=prod&&webpack -p --progress --colors",
    "publish-win":  "set NODE_ENV=prod&&webpack -p --progress --colors",
    "dev-mac": "export NODE_ENV=dev&&webpack-dev-server",
    "dev-win":  "set NODE_ENV=dev&&webpack-dev-server
}

config配置:


//其他代码省略...
var NODE_ENV = process.env.NODE_ENV;

var config = {
    //入口文件配置
    entry: path.resolve(__dirname, 'src/main.js'),
    resolve: {
        extentions: ["", "js"]//当requrie的模块找不到时,添加这些后缀
    },
    devtool: 'eval',
    //文件导出的配置
    output: {
        path: buildPath,
        filename: "app.js"
    },
    
    module: {
        loaders: [
            {
                test: /\.html$/, 
                loader: 'tmodjs',//对匹配的文件进行处理的loader 
                exclude: [nodemodulesPath]//排除node module中的文件
            }
        ]
    }
}

if(NODE_ENV === "prod"){//判断是生产环境执行生产配置
    delete config.devtool;
    config.plugins = [
    //压缩打包的文件
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        //supresses warnings, usually from module minification
        warnings: false
      }
    })];
}

之后dev环境执行命令:npm run dev-win
生产环境执行命令:npm run publish-win

常用plugins

  • 代码热替换, HotModuleReplacementPlugin

  • 将css成生文件,而非内联,ExtractTextPlugin

  • 报错但不退出webpack进程,NoErrorsPlugin

  • 多个 html共用一个js文件(chunk),可用CommonsChunkPlugin

  • 清理文件夹,Clean

  • 调用模块的别名ProvidePlugin,例如想在js中用$,如果通过webpack加载,需要将$与jQuery对应起来

参考文章

webpack使用优化

查看原文

赞 20 收藏 217 评论 17

於见 赞了文章 · 2016-09-10

javascript 回调函数 整理

为什么写回调函数

对于javascript中回调函数 一直处于理解,但是应用不好的阶段,总是在“别人家”的代码中看到很巧妙的回调,那时候会有wow cooooooool 的感觉。最近编码过程中,自己的代码能合理的应用回调会 更优雅些,索性做了一次对于回调函数“研究”。

我不是生产文章 我只是大自然的搬运工。

因为包括总结 和 拜读的时候,写的真好。

文章转自

回调函数定义

百度百科:回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

在JavaScript中,回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。如果没有名称(函数表达式),就叫做匿名回调函数。因此callback 不一定用于异步,一般同步(阻塞)的场景下也经常用到回调,比如要求执行某些操作后执行回调函数。

例子

一个同步(阻塞)中使用回调的例子,目的是在func1代码执行完成后执行func2。

var func1=function(callback){
    //do something.
    (callback && typeof(callback) === "function") && callback();
}
func1(func2);
    var func2=function(){
}

回调函数的使用场合

  • 资源加载:动态加载js文件后执行回调,加载iframe后执行回调,ajax操作回调,图片加载完成执行回调,AJAX等等。

  • DOM事件及Node.js事件基于回调机制(Node.js回调可能会出现多层回调嵌套的问题)。
    setTimeout的延迟时间为0,这个hack经常被用到,settimeout调用的函数其实就是一个callback的体现

  • 链式调用:链式调用的时候,在赋值器(setter)方法中(或者本身没有返回值的方法中)很容易实现链式调用,而取值器(getter)相对来说不好实现链式调用,因为你需要取值器返回你需要的数据而不是this指针,如果要实现链式方法,可以用回调函数来实现

  • setTimeout、setInterval的函数调用得到其返回值。由于两个函数都是异步的,即:他们的调用时序和程序的主流程是相对独立的,所以没有办法在主体里面等待它们的返回值,它们被打开的时候程序也不会停下来等待,否则也就失去了setTimeout及setInterval的意义了,所以用return已经没有意义,只能使用callback。callback的意义在于将timer执行的结果通知给代理函数进行及时处理。

函数也是对象

想弄明白回调函数,首先的清楚地明白函数的规则。在javascript中,函数是比较奇怪的,但它确确实实是对象。确切地说,函数是用Function()构造函数创建的Function对象。Function对象包含一个字符串,字符串包含函数的javascript代码。假如你是从C语言或者java语言转过来的,这也许看起来很奇怪,代码怎么可能是字符串?但是对于javascript来说,这很平常。数据和代码之间的区别是很模糊的。

//可以这样创建函数
var fn = new Function("arg1", "arg2", "return arg1 * arg2;");
fn(2, 3);   //6

  这样做的一个好处,可以传递代码给其他函数,也可以传递正则变量或者对象(因为代码字面上只是对象而已)。

  传递函数作为回调

  很容易把一个函数作为参数传递。
  

function fn(arg1, arg2, callback){
    var num = Math.ceil(Math.random() * (arg1 - arg2) + arg2);
    callback(num);//传递结果
}

fn(10, 20, function(num){
   console.log("Callback called! Num: " + num); 
});//结果为10和20之间的随机数

可能这样做看起比较麻烦,甚至有点愚蠢,为何不正常地返回结果?但是当遇上必须使用回调函数之时,你也许就不这样认为了!

  别挡道

  传统函数以参数形式输入数据,并且使用返回语句返回值。理论上,在函数结尾处有一个return返回语句,结构上就是:一个输入点和一个输出点。这比较容易理解,函数本质上就是输入和输出之间实现过程的映射。

  但是,当函数的实现过程非常漫长,你是选择等待函数完成处理,还是使用回调函数进行异步处理呢?这种情况下,使用回调函数变得至关重要,例如:AJAX请求。若是使用回调函数进行处理,代码就可以继续进行其他任务,而无需空等。实际开发中,经常在javascript中使用异步调用,甚至在这里强烈推荐使用!

  下面有个更加全面的使用AJAX加载XML文件的示例,并且使用了call()函数,在请求对象(requested object)上下文中调用回调函数。
  

function fn(url, callback){
    var httpRequest;    //创建XHR
    httpRequest = window.XMLHttpRequest ? new XMLHttpRequest() :   
        window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP"             ) : undefined;//针对IE进行功能性检测

    httpRequest.onreadystatechange = function(){
      if(httpRequest.readystate === 4 
                && httpRequest.status === 200){  //状态判断
          callback.call(httpRequest.responseXML);  
       }
    };
    httpRequest.open("GET", url);
    httpRequest.send();
}

fn("text.xml", function(){    //调用函数
   console.log(this);   //此语句后输出
});

console.log("this will run before the above callback.");  //此语句先输出

  我们请求异步处理,意味着我们开始请求时,就告诉它们完成之时调用我们的函数。在实际情况中,onreadystatechange事件处理程序还得考虑请求失败的情况,这里我们是假设xml文件存在并且能被浏览器成功加载。这个例子中,异步函数分配给了onreadystatechange事件,因此不会立刻执行。

  最终,第二个console.log语句先执行,因为回调函数直到请求完成才执行。

  上述例子不太易于理解,那看看下面的示例:

function foo(){
    var a = 10;
    return function(){
        a *= 2;
        return a;       
    };   
}
var f = foo();
f(); //return 20.
f(); //return 40.

  函数在外部调用,依然可以访问变量a。这都是因为javascript中的作用域是词法性的。函数式运行在定义它们的作用域中(上述例子中的foo内部的作用域),而不是运行此函数的作用域中。只要f被定义在foo中,它就可以访问foo中定义的所有的变量,即便是foo的执行已经结束。因为它的作用域会被保存下来,但也只有返回的那个函数才可以访问这个保存下来的作用域。返回一个内嵌匿名函数是创建闭包最常用的手段。
  

参考

  1. 理解 javascript 回调函数
  2. 理解与使用Javascript中的回调函数(这篇相当不错)
  3. javascript回调函数
查看原文

赞 9 收藏 54 评论 5

於见 发布了文章 · 2016-09-10

如何用CSS让一个容器水平垂直居中?

- 第一类(被居中的元素有固定的宽高)


效果:
clipboard.png

  1. 第一种方法(绝对定位 + 负margin)

    <div class="div1">   
        <div class="div2"></div> 
    </div>
    <style type="text/css">   
        .div1{
            width: 100px;
            height: 100px;
            border: 1px solid #000000;
            position: relative;
        }
        .div2{
            width: 40px;
            height: 40px;
            background-color: green;
            position: absolute;
            top: 50%;
            left: 50%;
            margin-top: -20px;
            margin-left: -20px;
        }
    </style>

2.第二种方法(绝对定位 + margin: auto)

    <div class="div1">   
        <div class="div2"></div> 
    </div>
    <style type="text/css">   
        .div1{
            width: 100px;
            height: 100px;
            border: 1px solid #000000;
            position: relative;
        }
        .div2{
            width: 40px;
            height: 40px;
            background-color: green;
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            margin: auto;
        }
    </style>

3.第三种方法(flex)

    <div class="div1">   
        <div class="div2"></div> 
    </div>
    <style type="text/css">   
        .div1{
            width: 100px;
            height: 100px;
            border: 1px solid #000000;
            display: flex;
        }
        .div2{
            width: 40px;
            height: 40px;
            background-color: green;
            margin: auto;
        }
    </style>

- 第二类(被居中的元素任意高度)


效果:
clipboard.pngclipboard.png

方法:display:table-cell:

<div class="div1">   
    <div class="div2">张三丰</div> 
</div>
<style type="text/css">   
    .div1{
        width: 100px;
        height: 100px;
        border: 1px solid #000000;
        display: table-cell;
        vertical-align: middle;
    }
    .div2{
        width: 40px;
        background-color: green;
        margin: 0 auto;
    }
</style>

- 第三类(被居中的元素 宽高都不限制)


效果:
clipboard.png

1.CSS3 flex

    <div class="div1">   
        <div class="div2">小阿三</div> 
    </div>
    <style type="text/css">   
        .div1{
            width: 100px;
            height: 100px;
            border: 1px solid #000000;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .div2{
            background-color: green;
        }
    </style>

2.transform:

    <div class="div1">   
        <div class="div2">小阿三</div> 
    </div>
    <style type="text/css">   
        .div1{
            width: 100px;
            height: 100px;
            border: 1px solid #000000;
            position: relative;
        }
        .div2{
            background-color: green;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }
    </style>

- 第四类(让图片居中)


效果:
clipboard.png

    <div class="div1">   
        <img data-original="images/2.png" alt=""> 
    </div>
    <style type="text/css">   
        .div1{
            width: 100px;
            height: 100px;
            border: 1px solid #000000;
            display: table-cell;
            vertical-align: middle;
            text-align: center;
        }
    </style>
查看原文

赞 0 收藏 1 评论 0

於见 发布了文章 · 2016-07-07

用node构建一个小小的HTTP服务

刚开始接触node,来一发http服务纪念一下。

定义:

官网上(http://www.nodejs.org)给Node下的定义是:“一个搭建在Chrome JavaScript运行时
上的平台,用于构建高速、可伸缩的网络程序。Node.js采用的事件驱动、非阻塞I/O模型,使它
既轻量又高效,并成为构建运行在分布式设备上的数据密集型实时程序的完美选择。”


Node为服务端JavaScript提供了一个事件驱动的、异步的平台。它把JavaScript带到服务端中
的方式跟浏览器把JavaScript带到客户端的方式几乎一模一样。它们都是事件驱动(用事件轮询)和非阻塞的I/O处理(用异步I/O)。

在Node中,I/O几乎总是在主事件轮询之外进行,使得服务器可以一直处于高效并且随时能
够做出响应的状态,就像NGINX一样。这样进程就更加不会受I/O限制,因为I/O延迟不会拖垮服
务器,或者像在阻塞方式下那样占用很多资源。因此一些在服务器上曾经是重量级的操作,在
Node服务器上仍然可以是轻量级的。

node常被用来构建服务器,在node中服务器和程序是一样的。下面是一个简单的HTTP服务器实现:(http.js文件)

const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});\\监听端口,被访问的时候做一些事情。

运行文件......没错!就这么实现了!

clipboard.png

查看原文

赞 2 收藏 2 评论 0

认证与成就

  • 获得 28 次点赞
  • 获得 0 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 0 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2016-01-26
个人主页被 477 人浏览