Css常见

定位

position属性:static、relative、absolute、fixed、sticky、inherit

  • static(默认):元素框正常生成。块级元素生成一个矩形框,作为文档流一部分,行内元素则会创建一个或多个行框,置于其父元素中。
  • relative:元素相对于之前正常文档流中的位置发生偏移,并且原先位置仍然被占据。发生偏移的时候,可能会覆盖其他元素。
  • absolute: 元素不再占文档流位置,并且相对于包含块进行偏移(包含块为最近一级外层元素position不为static的元素)
  • fiexd 元素不再占据文档流位置,并且当对于视窗进行定位
  • sticky Css3新增属性,粘性定位,相当于relative和fiexed混合,最初被当作是relative,相对于原来的位置进行偏移;一旦超过一定阈值后,会被当成fixed定位,相对于窗口进行定位。
  • inherit为从父元素继承
    其中偏移量有top、right、bottom、left四个属性。其单位有像素、百分比也可以是相对的单位比如rem等。

    尺寸

    我们一般布局中使用的尺寸单位除了px还可以包含以下单位:
  • 百分比:百分比的参照物是父元素,50%相当于父元素的50%
  • rem: 这个当对于复杂的设计图相当有用,它是html font-size的大小。
  • em:也是一个当对单位,相对于父元素的font-size,但是由于计算太麻烦,并不常用。

    盒子模型

    每个元素会形成一个矩形框,主要包括margin(外边距)+border(边框)+padding(内边距)+content(内容)
    Css中存在两种不同的盒子模型:标准W3C盒子模型和IE盒子模型。两种盒子模型差别主要体现在盒子的宽度,标准盒子模型中:width = content宽度,IE盒子模型中width = content + padding + border
    所以:
    标准盒子模型的盒子宽度:左右margin + 左右border + padding + width
    IE盒子模型的盒子宽度 = 左右marin + width
    我们可以通过css3的属性box-sizing设置不同的模型。值为content-box即为标准盒子模型,值为content-border即为IE盒子模型。

    浮动

    浮动最初只是被用来实现文字环绕的特效,只是我们后来把它用来布局。
    我个人是很反感float的,一般会用diaply:inline-block特性来实现布局,完全可以替代float。或是后来flex等等。
    深入浮动详见:CSS float浮动的深入研究、详解及拓展(一) 系列

布局

布局实现方式有很多种,基于定位、浮动等等,但是我这里推荐display:inline-block代替float布局,移动端直接flex

Share Comments

Webpack学习笔记

Webpack简介

Webpack是一个模块打包器 (module bundler),能够将任何资源如 JavaScript 文件、CSS 文件、图片等打包成一个或少数文件。

如果没有模块打包工具,我们就得在HTML中加载无数script标签了,这样的缺点显而易见,我们得关心文件的加载顺序和依赖关系,多个script标签也意外着多余的网络请求等等。

而Webpack就是为了解决这些问题而生的。

Webpack最新版本为v3,我这里就用的webapck3。如果之前用的是v1,可以阅读官方的v1迁移到v2,而v2和v3差别不大。

安装

依赖

安装Webpack前得先安装好Nodejs和npm

安装方式

Webpack安装分为全局安装和本地安装
全局安装虽然使用很方便,但它不会包括在项目的依赖模块列表中。
更规范化的操作是使用本地安装CLI包,然后用相对路径或是npm脚本中运行它。

本地安装

先用npm init 一路回车来创建一个项目,得到package.json

然后

1
npm install webpack --save-dev --registry=https://registry.npm.taobao.org

安装webpack,我这里使用了淘宝镜像

为方便后面实例,再安装个lodash:

1
npm install lodash --save --registry=https://registry.npm.taobao.org

使用Webpack

npm scripts中使用

首先创建src目录和index.js文件

1
2
mkdir src && cd src
vim index.js

index.js内容很简单,简单输入数组中各个数的平方,如下:

1
2
3
4
5
6
var _ = require('lodash');

console.log(_.map([1,2,3,4,5,6], function(n) {
return n*n;
})
);

备注,关于这里的lodash模块引用:

1
2
3
4
5
6
7
// 这里引用lodash有两种方式,分别如下:
var _ = require('lodash')
import _ from 'lodash'

// 这里两种方式在webpack中都能工作
// 只是第一种是常见在nodejs开发中,是commonJs规范的一部分
// 第二种属于ES6中新的模块化加载规范

然后回到项目根目录,编辑package.json文件的scripts部分,新增build命令,如下:

1
2
3
"scripts": {
"build": "webpack src/index.js dist/bundle.js",
}

然后

1
npm run build

就会生成dist/bundle.js,使用

1
node dist/bundle.js

就会运行该文件,也可以使用html将其跑在浏览器端。

使用Webpack配置文件

上面的的实例我们是使用webpack命令行,但是如果使用更多的功能,我们就得使用webpack的配置文件

一般的,我们会在项目根目录下创建一个配置文件:webpack.config.js,Webapck会默认寻找该文件,使用–config [filename]可以指定一个配置文件。

我们来使用配置文件做上一个命令行中的事,新建webpack.config.js,内容如下:

1
2
3
4
5
6
7
8
9
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
};

package.json中的build只用写webpack:

1
"build": "webpack",

然后:

1
npm run build

依然会像命令行一样成功打包。

更专业一点

打包前我们需要先删除dist目录,这里使用del-cli工具,可以不用顾虑操作系统差别。

1
npm install del-cli --save-dev --registry=https://registry.npm.taobao.org

接着更新package.json中npm脚本如下:

1
2
3
4
5
6
"scripts": {
"prebuild": "del-cli dist -f", // 删除目录
"build": "webpack",
"execute": "node dist/bundle.js", // 运行打包出来的文件
"start": "npm run build -s && npm run execute -s" // 打包
}

这样我们使用起来就很方便了。

Webpack加载器 Loaders

加载器可以提前帮我们转换或操作特定类型的文件,比如通过Babel加载器把ES6转为ES5,打包Css文件图片等等都会用到loader。

这里我们以用Babel把ES6转为ES5为例,首先把刚才的index.js改为ES6写法。
vim index.js:

1
2
3
import _ from 'lodash';

console.log(_.map([1,2,3,4,5,6], n => n*n));

安装依赖的包:

1
npm i -D babel-core babel-loader babel-preset-es2015 --registry=https://registry.npm.taobao.org

然后新建.babelrc文件,内容如下:

1
2
3
{
"presets": ["es2015"]
}

编辑webapck.config.js文件如下(新增module):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
}
};

然后执行:

1
npm run build

loader的作用很大,常见还有style-loader,file-loader等等。这个大家可以在实践中发掘。

插件

Loader和Plugins的不同

Loader主要在加载两字,是用于预处理文件的。而插件一般是用来增强Webpack功能的

使用插件

这里只用CleanWebpackPlugin插件举一个简单例子,CleanWebpackPlugin用来删除目录的(和我们上面的del-cli功能差不多)
安装包:

1
npm install clean-webpack-plugin --save-dev --registry=https://registry.npm.taobao.org

编辑webapck.config.js文件如下(新增plugins):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
},

plugins: [
new CleanWebpackPlugin(['dist'])
]
};

然后使用

1
npm run build

这里只是简单讲下plugins用法,Webpack还有许多有用的插件

多文件打包

上述例子只是只有一个输入文件index.js,一个输出文件bundle.js,假如我们有多个文件分别打包怎么办呢?
写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
const path = require('path');

module.exports = {
entry: {
index: './src/index.js',
app: './src/app.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js'
}
};

这样就可以通过入口文件动态生成bundle文件。

开发环境

webpack提供许多供开发时使用的功能,下面简单介绍下:

代码映射(Source map)

Webpack在打包后如果发生错误,很难定位到,Source map就是解决这个问题的,它可以把编译后的代码映射回原始源码,便于我们定位错误。Webpack提供了十种风格的代码映射,具体见:官方手册devtool,这里我们以inline-source-map为例。

启用Source map很简单,就是module.exports中新增devtool属性,然后指定映射风格。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
devtool: 'inline-source-map',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
},

plugins: [
new CleanWebpackPlugin(['dist'])
]
};

这样我们在打包时便能很清楚的在控制台上看到相应错误。

Webpack-dev-server插件

Webpack-dev-server提供了一个简单的服务器环境,并提供实时加载代码功能。
先安装包:

1
npm install webpack-dev-server --save-dev --registry=https://registry.npm.taobao.org

启用只需配置文件中设置devServer,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
devtool: 'inline-source-map',
devServer: {
contentBase: path.resolve(__dirname, 'dist')
},
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
},

plugins: [
new CleanWebpackPlugin(['dist'])
]
};

新增npm scripts,增加一条run-server命令,编辑package.json:

1
"start:dev": "webpack-dev-server --open"

然后运行:

1
npm run start:dev

浏览器就会自动加载应用的页面默认在:localhost:8080显示,当然也可以通过在devServer设置类似port: 9000指定端口,更多设置请查看官方文档手册。

生产环境

命令行执行webpack -p 时就会构建生产环境应用,它会完成以下步骤:

  • 使用 UglifyJsPlugin (webpack.optimize.UglifyJsPlugin) 压缩 JS 文件 (此插件和 uglifyjs-webpack-plugin 相同)
  • 运行 LoaderOptionsPlugin 插件,这个插件是用来迁移的,见 document
  • 设置 NodeJS 的环境变量,触发某些 package 包以不同方式编译

在配置文件中使用process.env.NODE_ENV环境变量

Webpack -p 相当于 webpack –optimize-minimize –define process.env.NODE_ENV=”‘production’”,但是在Webpack配置文件无法读取process.env.NODE_ENV环境变量

这里我们可以使用cross-env包:

1
npm install --save-dev cross-env --registry=https://registry.npm.taobao.org

设置package.json的build为生产版本

1
"build": "cross-env NODE_ENV=production webpack -p",

现在可以在配置文件中使用process.env.NODE_ENV了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
devtool: 'inline-source-map',
devServer: {
contentBase: path.resolve(__dirname, 'dist')
},
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: process.env.NODE_ENV === 'production' ? '[name].[chunkhash].js' : '[name].bundle.js' // 根据环境为文件命名
},
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
},

plugins: [
new CleanWebpackPlugin(['dist'])
]
};

多配置文件配置

在常规开发中,我们一般会为开发环境和生产环境设置不同的配置文件。这里我们先一个基本文件,包含所有环境都包含的配置,然后使用webapck-merge将它和特定环境的配置文件合并并导出。

首先安装webpack-merge:

1
npm install --save-dev webpack-merge --registry=https://registry.npm.taobao.org

webpack.common.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
},

plugins: [
new CleanWebpackPlugin(['dist'])
]
};

webpack.dev.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const path = require('path');
const webpack = require('webpack');
const Merge = require('webpack-merge');
const CommonConfig = require('./webpack.common.js');

module.exports = Merge(CommonConfig, {
devtool: 'inline-source-map',
devServer: {
contentBase: path.resolve(__dirname, 'dist')
},
output: {
filename: '[name].bundle.js'
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
}),
new webpack.NamedModulesPlugin()
]
});

webpack.prod.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const webpack = require('webpack');
const Merge = require('webpack-merge');
const CommonConfig = require('./webpack.common.js');

module.exports = Merge(CommonConfig, {
devtool: 'cheap-module-source-map',
output: {
filename: '[name].[chunkhash].js'
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new webpack.optimize.UglifyJsPlugin()
]
});

然后在package.json中新增build:dev和build:prod scripts:

1
2
"build:dev": "webpack-dev-server --open --config webpack.dev.js",
"build:prod": "webpack --progress --config webpack.prod.js"

现在只需执行npm run build:dev或npm run build:prod便可以得到开发版或者生产版了

代码分离

举个例子,比如我们有两个js文件,都引入了lodash,在打包时这两个入口文件都会引入lodash,这很大程度上造成了冗余,在同一个页面我们只需引入一个lodash就可以了。

我们可以使用CommonChunkPlugin插件来将相同部分提取出来放到一个单独模块中。

为达到演示效果,新增一个src/test.js:

1
2
3
4
5
const _ = require('lodash');

var str = _.join(['a', 'b', 'c']);

console.log(str);

编辑webpack.config.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const webpack = require('webpack');
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
devtool: 'inline-source-map',
devServer: {
contentBase: path.resolve(__dirname, 'dist')
},
entry: {
index: './src/index.js',
test: './src/test.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js'
},
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
},

plugins: [
new HtmlWebpackPlugin({
title: 'webpack demo',
filename: 'index.html'
}),
new CleanWebpackPlugin(['dist']),
new webpack.optimize.CommonsChunkPlugin({
name: 'common' // 抽取出的模块的模块名
}),
]
};

这样就会打包出公共的common.bundle.js和各自的index.bundle.js和test.bundle.js文件。

懒加载(Lazy loading)

我们可以使用import()来实现懒加载,在需要的时候才加载相应的模块,减少应用初始化时加载暂不需要的模块的压力,提高程序运行速度。

编辑src/hello.js

1
2
3
4
5
console.log("The hello.js module has loaded!");

export default function hello() {
console.log('hello');
}

编辑src/say.js

1
2
3
4
5
6
7
const btn = document.getElementById(".clickMe");
btn.onclick = function() {
import(/* webpackChunkName: "hello" */ './hello').then(function(module) {
var hello = module.default;
hello();
});
};

编辑webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
devtool: 'inline-source-map',
devServer: {
contentBase: path.resolve(__dirname, 'dist')
},
entry: {
say: './src/say.js',
hello: './src/hello.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js'
},
module: {
rules: [
]
},

plugins: [
new HtmlWebpackPlugin({
title: 'webpack demo',
filename: 'index.html'
}),
new CleanWebpackPlugin(['dist'])
]
};

打包后新建一个html文件,包含一个id为clickMe的button,然后运行html,点击按钮。就会看到效果。

好了,webpack的总结就到这里了,这个只是大致入门了解,更多的还需要过一遍官方文档,然后结合实际项目才能使用好webpack。

Share Comments

Npm常见

关于安装

Npm安装分为局部安装和全局安装

全局安装

通过 加 –global/-g 安装

包会被安装在{prefix}/lib/node_modules下面

其中{prefix}通常是/usr/或/usr/local

通过以下命令可以获取具体prefix

1
npm config get prefix

通过npm list可以查看全局路径下的所有包(加–depth=0可以缩短显示效果)

局部安装

包会被安装到项目根目录下的node_modules文件夹下面,属于当前用户的。

一般依赖package.json文件安装
通过npm init命令一路回车就会在根目录下面创建package.json文件

1
2
3
4
5
6
7
8
9
10
11
{
"name": "project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

main表示程序入口文件,scripts指定运行脚本命令缩写。

比如安装underscore

1
npm install underscore

就会发现dependencies已经被添加

1
2
3
4
5
6
{
...
"dependencies": {
"underscore": "^1.8.3"
}
}

其中插入符号(^)表示安装不低于此版本的包。
npm默认安装时为把安装的包存为dependencies域,如果指定–save-dev就会填入devDependencies
其中:

  • Dependencies为程序运行必备的包
  • DevDependencies 是开发时所需要的包

安装过程

npm安装模块过程:

  • 发出npm install命令
  • npm 向 registry 查询模块压缩包的网址
  • 下载压缩包,存放在~/.npm目录
  • 解压压缩包到当前项目的node_modules目录

删除包

1
npm uninstall underscore

更新包

首先检查包是否有有更新

1
2
3
4
npm outdated

Package Current Wanted Latest Location
underscore 1.8.2 1.8.3 1.8.3 project

Current代表当前的包版本,Lastest为最新版本,Wanted为在不破坏现有代码情况下,可以更新到的版本号。

npm v5中新增package-lock.json 其目的是确保在所有主机上安装同样的依赖库,无论是在node_modules目录或package.json文件修改依赖树,都会自动记录下来。

更新具体包:

1
npm update unserscore

更新所有过期包

1
npm update

查找包

1
npm search

重新安装项目依赖

1
npm install

管理缓存

npm安装时会保存副本,这样下次再安装时,就不需要联网,存储存储在默认用户目录下的.npm文件夹(windows为npm-cache)

清理缓存

1
npm cache clean

使用淘宝镜像加速安装速度

具体访问:https://npm.taobao.org/

常见问题:

1, 安装时加–verbose可以查看具体信息
2, 如果用root用户或sudo还是提示权限不足:

1
2
npm config set user 0
npm config set unsafe-perm true
Share Comments