前端模块化&&Less的使用

前端模块化

函数封装

函数一个功能就是实现特定逻辑的一组语句打包,而且JavaScript的作用域就是基于函数的,所以把函数作为模块化的第一步是很自然的事情,在一个文件里面编写几个相关函数就是最开始的模块

示例一:

function fn1(){
    ...
}
function fn2(){
    ...
}

// 缺点:污染全局变量,可能发生变量名冲突,模块成员之间没联系。

对象

为了解决上面问题,对象的写法应运而生,可以把所有的模块成员封装在一个对象中

示例二:

var myModule = {
    var1: 1,
    var2: 2,
    fn1: function(){
        ...
    },
    fn2: function(){
        ...
    }
}

// 调用:
myModule.fn2();
// 缺陷:外部可以随意修改内部成员,会产生意外的安全问题
myModule.var1 = 100;

立即执行函数

示例三:

var myModule = (function(){
    var var1 = 1;
    var var2 = 2;
    function fn1(){
        ...
    }
    function fn2(){
        ...
    }
    return {
        fn1: fn1,
        fn2: fn2
    }
})();
放大模式和宽放大模式

放大模式
如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用"放大模式"(augmentation)。
示例四:

var myModule = (function(mod){
    mod.fn3 = function(){
        ...
    };
    return mod;
})(module1);

上面的代码为module1模块添加了一个新方法m3(),然后返回新的module1模块。

宽放大模式
在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上一节的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用"宽放大模式"。
示例五:

var myModule = (function(mod){
    ...
    return mod;
})(window.module1 || {});

与"放大模式"相比,"宽放大模式"就是"立即执行函数"的参数可以是空对象。

示例六:

var myModule = (function($,Angular){
    ...
})(jQuery,Angular);

模块的规范
先想一想,为什么模块很重要?
因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。
但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写法,我有我的写法,岂不是乱了套!考虑到Javascript模块现在还没有官方规范,这一点就更重要了。
目前,通行的Javascript模块规范共有两种:CommonJS 和 AMD。

CommonJs

  1. 定义模块
    根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global(全局)对象的属性
  2. 模块输出
    模块只有一个出口,module.exports对象,我们需要把模块希望输出的内容放入该对象
  3. 加载模块
    加载模块使用require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象

示例:

// 模块定义 myModel.js
var name = 'xxx';
function printName(){
    console.log(name);
}
function printFullName(firstName){
    console.log(firstName + name);
}
module.exports = {
    printName: printName,
    printFullName: printFullName
}

// 加载模块
var nameModule = require('./myModel.js');
nameModule.printName();

不同的实现对require时的路径有不同要求,一般情况可以省略js拓展名,可以使用相对路径,也可以使用绝对路径,甚至可以省略路径直接使用模块名(前提是该模块是系统内置模块)

AMD

AMD 即Asynchronous Module Definition,中文名是异步模块定义的意思。它是一个在浏览器端模块化开发的规范

由于不是JavaScript原生支持,使用AMD规范进行页面开发需要用到对应的库函数,也就是大名鼎鼎RequireJS,实际上AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出

requireJS主要解决两个问题:

  1. 多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
  2. js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长

一个使用requireJS的例子

// 定义模块 myModule.js
define(['dependency'],function(){
    var name = 'xxx';
    function printName(){
        console.log(name);
    }
    return {
        printName: printName
    };
});

// 加载模块
require(['myModule'],function(my){
    my.printName();
});

语法:
requireJS定义了一个函数define,它是全局变量,用来定义模块
define(id,dependencies,factory);
// id: 可选参数,用来定义模块的标识,如果没有提供该参数,脚本文件名(去掉扩展名)
// dependencies: 是一个当前模块依赖的模块名称数组
// factory: 工厂方法,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值

在页面上使用require函数加载模块
require([dependencies],function(){ ... })
// 第一个参数是一个数组,表示所依赖的模块
// 第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块

require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。

CMD

CMD 即Common Module Definition通用模块定义,CMD规范是国内发展出来的,就像AMD有个requireJS,CMD有个浏览器的实现SeaJS,SeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同

语法:
Sea.js 推崇一个模块一个文件,遵循统一的写法
define(id,deps,factory)
因为CMD推崇 1. 一个文件一个模块,所以经常就用文件名作为模块id
2. CMD推崇依赖就近,所以一般不在define的参数中写依赖,在factory中写

factory有三个参数
function(require,exports,module)
// require 是 factory 函数的第一个参数
// require 是一个方法,接受 模块标识 作为唯一参数,用来获取其他模块提供的接口
require(id)

// exports 是一个对象,用来向外提供模块接口

// module 是一个对象,上面存储了与当前模块相关联的一些属性和方法

一个示例:
// 定义模块 myModule.js

define(function(require,exports,module){
   var $ = require('jquery.js');
   $('div').addClass('active'); 
});

// 加载模块

seajs.use(['myModule.js'],function(my){
    ...
});

AMD与CMD区别

  1. AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
  2. CMD推崇就近依赖,只有在用到某个模块的时候再去require
    这种区别各有优劣,只是语法上的差距,而且requireJS和SeaJS都支持对方的写法

AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同

很多人说requireJS是异步加载模块,SeaJS是同步加载模块,这么理解实际上是不准确的,其实加载模块都是异步的,只不过AMD依赖前置,js可以方便知道依赖模块是谁,立即加载,而CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块,这也是很多人诟病CMD的一点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略

同样都是异步加载模块,AMD在加载模块完成后就会执行该模块,所有模块都加载执行完后会进入require的回调函数,执行主逻辑,这样的效果就是依赖模块的执行顺序和书写顺序不一定一致,看网络速度,哪个先下载下来,哪个先执行,但是主逻辑一定在所有依赖加载完成后才执行

CMD加载完某个依赖模块后并不执行,只是下载而已,在所有依赖模块加载完成后进入主逻辑,遇到require语句的时候才执行对应的模块,这样模块的执行顺序和书写顺序是完全一致的

这也是很多人说AMD用户体验好,因为没有延迟,依赖模块提前执行了,CMD性能好,因为只有用户需要的时候才执行的原因

LESS

LESS简介

Less 是一门 CSS 预处理语言,它扩展了 CSS 语言,增加了变量、Mixin、函数等特性,使 CSS 更易维护和扩展。
Less 可以运行在 Node 或浏览器端。

变量

和JS中的变量一样,只是LESS的变量定义不是使用VAR而是使用@。

// LESS代码
@link-color: #428bca;
@link-color-hover: darken(@link-color, 10%);

a {
    color: @link-color;
    &:hover {
        color: @link-color-hover;
    }
}

.box {
    color: @link-color;
}

// -> 编译为css的结果
a {
    color: #428bca;
}

a:hover {
    color: #3071a9;
}

.box {
    color: #428bca;
}

除了上述用变量存储公用的属性值,我们还可以用变量存储公用的URL、选择器等等

// LESS代码
.@{selector} {
    width: 100px;
    height: 100px;
    @{property}: #000;
    background: url("@{bgImg}/test.png");

    &:after {
        display: block;
        content: @@var;
    }
}
@selector: box;
@bgImg: '../img';
@property: color;
@name: 'xxx';
@var: 'name';

 //->编译为CSS的结果
.box {
    width: 100px;
    height: 100px;
    color: #000;
    background: url("../img/test.png");
}

.box:after {
    display: block;
    content: "xxx";
}

Mixin混合

基本使用
// LESS代码
.public {
    width: 100px;
    height: 100px;
}

nav ul {
    .public;
    list-style: none;
}

//->编译为CSS的结果
.public {
    width: 100px;
    height: 100px;
}

nav ul {
    width: 100px;
    height: 100px;
    list-style: none;
}

观察上述的代码,我们发现其实nav ul是把public中设定的样式属性值copy了一份到自己的样式中。如果你想在编译完成的结果中不输出public这个样式的结果,只需要按照下述的代码编写即可:

// LESS代码
.public() {  //在选择器后加上()就不编译
    width: 100px;
    height: 100px;
}

nav ul {
    .public;
    list-style: none;
}

//->编译为CSS的结果
nav ul {
    width: 100px;
    height: 100px;
    list-style: none;
}
Extend

虽然在上述的案例中,nav ul把public中的样式继承了过来,但是原理却是把代码copy一份过来,这样编译后的CSS中依然会存留大量的冗余CSS代码,为了避免这一点,我们可以使用extend伪类来实现样式的继承使用。

// LESS代码
.public {
    width: 100px;
    height: 100px;
}

nav ul {
    &:extend(.public);     // &:extend( ... )
    list-style: none;
}

或者

// LESS代码
.public {
    width: 100px;
    height: 100px;
}

nav ul:extend(.public) {     // 选择器:extend( ... )
    list-style: none;
}

//->编译为CSS的结果
.public, nav ul {
    width: 100px;
    height: 100px;
}

nav ul {
    list-style: none;
}
命名空间和作用域

在LESS的语法中,我们可以指定命名空间,实现在一个盒子中层级嵌套式的编写。下面案例中,.box就是命名空间,里面的img、.gray都是这个空间下的样式,调取的话需要.box > .gray。

// LESS代码
.box {
    width: 100px;
    height: 100px;
    img {
        width: 100%;
        height: 100%;
    }
    .gray {
        color: #eee;
    }
    &:hover {
        background: green;
    }
}

#nav {
    .box;
}

#header {
    .box > .gray;
}

//->编译为CSS的结果
.box {
    width: 100px;
    height: 100px;
}

.box img {
    width: 100%;
    height: 100%;
}

.box .gray {
    color: #eee;
}

.box:hover {
    background: green;
}

#nav {
    width: 100px;
    height: 100px;
}

#nav img {
    width: 100%;
    height: 100%;
}

#nav .gray {
    color: #eee;
}

#nav:hover {
    background: green;
}

#header {
    color: #eee;
}

在LESS中定义了命名空间就创建了一个私有的作用域,在这个私有作用域中使用的变量都是先看一下自己作用域中有没有,没有的话,在向上一级查找(类似于JS的作用域链)。

// LESS代码
@color: #ccc;
.box {
    @color: #eee;
    .gray {
        color: @color;
    }
}

.box2 {
    .gray {
        color: @color;
    }
}

//->编译为CSS的结果
.box .gray {
    color: #eee;
}

.box2 .gray {
    color: #ccc;
}
!important

在调用的混合集后面追加 !important 关键字,可以使混合集里面的所有属性都继承 !important:

// LESS代码
@color: #ccc;
.box {
    @color: #eee;
    .gray {
        color: @color;
    }
}

nav ul {
    .box !important;
}

//->编译为CSS的结果
.box .gray {
    color: #eee;
}

nav ul .gray {
    color: #eee !important;
}
Parametric Mixins

如同JS一样,LESS也可以向函数一样设定形参数,这个技巧在我们的项目中会被经常的使用到,例如:处理CSS3的兼容问题

// LESS代码
.transition(@property: all; @duration: 1s; @function: linear; @delay: 0s;) {
    -webkit-transition: @property @duration @function @delay;
    -moz-transition: @property @duration @function @delay;
    -ms-transition: @property @duration @function @delay;
    -o-transition: @property @duration @function @delay;
    transition: @property @duration @function @delay;
}

.box1 {
    .transition;
}

.box2 {
    .transition(@duration: 2s);
}

.box3 {
    .transition(@duration: 2s; @property: width;);
}

//->编译为CSS的结果
.box1 {
    -webkit-transition: all 1s linear 0s;
    -moz-transition: all 1s linear 0s;
    -ms-transition: all 1s linear 0s;
    -o-transition: all 1s linear 0s;
    transition: all 1s linear 0s;
}

.box2 {
    -webkit-transition: all 2s linear 0s;
    -moz-transition: all 2s linear 0s;
    -ms-transition: all 2s linear 0s;
    -o-transition: all 2s linear 0s;
    transition: all 2s linear 0s;
}

.box3 {
    -webkit-transition: width 2s linear 0s;
    -moz-transition: width 2s linear 0s;
    -ms-transition: width 2s linear 0s;
    -o-transition: width 2s linear 0s;
    transition: width 2s linear 0s;
}

此外我们需要值得注意的是,LESS中也有arguments。

// LESS代码
.transition(@property: all; @duration: 1s; @function: linear; @delay: 0s;) {
    -webkit-transition: @arguments;
    transition: @arguments;
}

.box1 {
    .transition;
}

//->编译为CSS的结果
.box1 {
    -webkit-transition: all 1s linear 0s;
    transition: all 1s linear 0s;
}

我们还可以把变量像JS的函数一样操作,不仅仅有参数,还有返回值。

// LESS代码
.average(@x,@y) {
    @result: ((@x + @y) / 2);
}

div {
    .average(16px,50px); // 传入参数
    padding: @result; // 返回值
}

//->编译为CSS的结果
div {
    padding: 33px;
}
模式匹配

有些情况下,我们想根据传入的参数来改变混合的默认呈现,比如下面这个例子:

.mixin (@s, @color) { ... }

.class {
  .mixin(@switch, #888);
}

如果想让.mixin根据不同的@switch值而表现各异,如下这般设置:

.mixin (dark, @color) {
    color: darken(@color, 10%);
}

.mixin (light, @color) {
    color: lighten(@color, 10%);
}

.mixin (@_, @color) {
    display: block;
}

现在,如果运行:

@switch: light;

.class {
    .mixin(@switch, #888);
}

//->编译为CSS的结果
.class {
  color: #a2a2a2;
  display: block;
}

如上,.mixin就会得到传入颜色的浅色。如果@switch设为dark,就会得到深色。

具体实现如下:
第一个混合定义并未被匹配,因为它只接受dark做为首参
第二个混合定义被成功匹配,因为它只接受light
第三个混合定义被成功匹配,因为它接受任意值

只有被匹配的混合才会被使用。变量可以匹配任意的传入值,而变量以外的固定值就仅仅匹配与其相等的传入值。

我们也可以匹配多个参数:

.mixin (@a) {
  color: @a;
}
.mixin (@a, @b) {
  color: fade(@a, @b);
}
Mixin Guards

我们可以在mixin中设置条件;常用的条件运算符:>、>=、<、<=、=;我们设定的条件还可以使用IS函数:iscolor、isnumber、isstring、iskeyword、isurl、ispixel、ispercentage...

// LESS代码
.mixin (@a) when (lightness(@a) >= 50%) {
    background-color: black;
}

.mixin (@a) when (lightness(@a) < 50%) {
    background-color: white;
}

.box1 {
    .mixin(#ddd);
}

.box2 {
    .mixin(#555);
}

//->编译为CSS的结果
.box1 {
    background-color: black;
}

.box2 {
    background-color: white;
}

when是在设置条件,除了像上面的写法外,我们还可以通过when设置多个条件,而且条件中可以使用is函数。

// LESS代码:使用is函数
.mixin (@a; @b: 0) when (isnumber(@b)) { ... }
.mixin (@a; @b: black) when (iscolor(@b)) { ... }

// LESS代码:多条件,可以使用and或者逗号间隔(与条件)
.mixin (@a) when (isnumber(@a)) and (@a > 0) { ... }
.mixin (@a) when (isnumber(@a)) , (@a > 0) { ... }

 // LESS代码:使用not关键字实现或条件
.mixin (@b) when not (@b > 0) { ... }

我们还可以通过与&特性结合实现'if'类型的语句。

// LESS代码:这里的意思是如果为true, .box的文字颜色才是白色
@my-option: true;
& when (@my-option = true) {
    .box {
        color: white;
    }
}

Loops

在Less中,混合可以调用它自身。这样,当一个混合递归调用自己,再结合Guard条件表达式,就可以写出循环结构。使用递归循环最常见的情况就是生成栅格系统的CSS:

// LESS代码
.generate-columns(4);
.generate-columns(@n, @i: 1) when (@i <= @n) {
    .column-@{i} {
        width: {@i * 100% / @n};
    }
    .generate-columns(@n, (@i + 1));
}

//->输出的CSS
.column-1 {
    width: 25%;
}

.column-2 {
    width: 50%;
}

.column-3 {
    width: 75%;
}

.column-4 {
    width: 100%;
}

Merge

Merge特性可以从多个属性中将值,集合到某一个样式属性的列表中(也就是多样式效果)。在编写的时候,+代表以逗号分隔,+_代表多个之前以空格分隔。

// LESS代码
.mixin() {
    box-shadow+: inset 0 0 10px #555;
}

.myclass {
    .mixin;
    box-shadow+: 0 0 20px black;
}

.mixin2() {
    transform+_: scale(2);
}

.myclass2 {
    .mixin2;
    transform+_: rotate(45deg);
}

//->输出的CSS
.myclass {
    box-shadow: inset 0 0 10px #555, 0 0 20px black;
}

.myclass2 {
    transform: scale(2) rotate(45deg);
}

Parent Selectors

&运算符其实就是让当前的选择器和父级选择器按照特定的规则进行连接

// LESS代码
.box {
    color: blue;
    &:hover {
        color: green;
    }

    &-top {
        height: 30px;
    }

    &-center {
        height: 500px;
    }

    // 多个&&
    & + &-top {
        color: red;
    }

    & &-top {
        color: grey;
    }

    &&-top {
        color: black;
    }

    &, &-top {
        color: orange;
    }
}

//->输出的CSS
.box {
    color: blue;
}

.box:hover {
    color: green;
}

.box-top {
    height: 30px;
}

.box-center {
    height: 500px;
}

.box + .box-top {
    color: red;
}

.box .box-top {
    color: grey;
}

.box.box-top {
    color: black;
}

.box, .box-top {
    color: orange;
}

改变选择器顺序,下面的案例中,选择器.no-border-radius &会前置插入它的父选择器.header .menu,最后变成.no-border-radius .header .menu形式输出:

// LESS代码
.header {
    .menu {
        border-radius: 5px;
        .no-border-radius & {
            background-image: url('xxx.png');
        }
    }
}

//->输出的CSS
.header .menu {
    border-radius: 5px;
}

.no-border-radius .header .menu {
    background-image: url('images/button-background.png');
}

Import Directives

从其他样式表中导入样式

// LESS代码
@import "public.less";

.box {
    &:after {
        .clear;
    }
}

//->输出的CSS:会把public中的样式也输出
.clear {
    display: block;
    height: 0;
    content: "";
    clear: both;
    zoom: 1;
}

.box:after {
    display: block;
    height: 0;
    content: "";
    clear: both;
    zoom: 1;
}

我们发现上述的操作虽然实现了调取使用,但是会把public中的less也编译到了自己的这个css中,如果不想编译的话,我们需要配置一些参数:

// LESS代码
@import(reference) "public.less";

.box {
    &:after {
        .clear;
    }
}

//->输出的CSS:
.box:after {
    display: block;
    height: 0;
    content: "";
    clear: both;
    zoom: 1;
}

除了reference以外我们还可以配置一些其他的参数值:
// inline: 在输出中包含源文件但不加工它
// less: 将文件作为Less文件对象,无论是什么文件扩展名
// css: 将文件作为css文件对象,无论是什么文件扩展名
// once: 只包含文件一次(默认行为)
// multiple: 包含文件多次

函数 & 运算

运算提供了加,减,乘,除操作;我们可以做属性值和颜色的运算,这样就可以实现属性值之间的复杂关系。LESS中的函数一一映射了JavaScript代码,如果你愿意的话可以操作属性值。

// LESS代码
@the-border: 1px;
@base-color: #111;
@red: #842210;

#header {
    color: @base-color * 3;
    border-left: @the-border;
    border-right: @the-border * 2;
}

#footer {
    color: @base-color + #003300;
    border-color: desaturate(@red,10%);
}

//->输出的CSS:
#header {
  color: #333;
  border-left: 1px;
  border-right: 2px;
}
#footer { 
  color: #114411;
  border-color: #7d2717;
}

color 函数

LESS 提供了一系列的颜色运算函数. 颜色会先被转化成 HSL 色彩空间, 然后在通道级别操作:

lighten(@color, 10%);     // 返回一种比 @color 更亮的颜色
darken(@color, 10%);      // 返回一个比 @color 更暗的颜色

saturate(@color, 10%);    // 返回的颜色比 @color 的饱和度高10%
desaturate(@color, 10%);  // 返回的颜色比 @color 的饱和度低10%

fadein(@color, 10%);      // 返回的颜色比 @color 的透明度低
fadeout(@color, 10%);     // 返回一个比 @color 更透明的颜色
fade(@color, 50%);        // 返回 @color ,透明度50%

spin(@color, 10);         // 返回一个比 @color 大10度的颜色
spin(@color, -10);        // 返回一个比 @color 小10度的颜色

mix(@color1, @color2);    // 返回 @color1 和 @color2 的混合

使用:

@base: #f04615;

.class {
    color: saturate(@base, 5%);
    background-color: lighten(spin(@base, 8), 25%);
}

你还可以提取颜色信息:

hue(@color);        // 返回 @color 的“色相”频道
saturation(@color); // 返回 @color 的“饱和度”通道
lightness(@color);  // 返回@ color的“明度”通道

如果你想在一种颜色的通道上创建另一种颜色,这些函数就显得那么的好用,例如:
@new: hsl(hue(@old), 45%, 90%);
@new 将会保持 @old的 色调, 但是具有不同的饱和度和亮度

Math 函数

LESS提供了一组方便的数学函数,你可以使用它们处理一些数字类型的值:

round(1.67); // returns `2` 四舍五入
ceil(2.4);   // returns `3` 向上取整
floor(2.6);  // returns `2` 向下取整

如果你想将一个值转化为百分比,你可以使用percentage 函数:
percentage(0.5); // returns 50%

避免编译

有时候我们需要输出一些不正确的CSS语法或者使用一些 LESS不认识的专有语法.
要输出这样的值我们可以在字符串前加上一个 ~, 例如:

.class {
  filter: ~"ms:alwaysHasItsOwnSyntax.For.Stuff()";
}

我们可以将要避免编译的值用 “”包含起来,输出结果为:

.class {
  filter: ms:alwaysHasItsOwnSyntax.For.Stuff();
}

JavaScript 表达式

JavaScript 表达式也可以在.less 文件中使用. 可以通过反引号的方式使用:

@var: `"hello".toUpperCase() + '!'`;

输出:
@var: "HELLO!";

注意你也可以同时使用字符串插值和避免编译:

@str: "hello";
@var: ~`"@{str}".toUpperCase() + '!'`;

输出:
@var: HELLO!;

它也可以访问JavaScript环境:

@height: `document.body.clientHeight`;

如果你想将一个JavaScript字符串解析成16进制的颜色值, 你可以使用 color 函数:

@color: color(`window.colors.baseColor`);
@darkcolor: darken(@color, 10%);

在客户端使用

引入你的.less样式文件的时候要设置rel属性值为"stylesheet/less":
<link rel="stylesheet/less" type="text/css" href="styles.less">

然后点击页面顶部download按钮下载 less.js, 在<head> 中引入:
<script src="less.js" type="text/javascript"></script>

注意你的less样式文件一定要在引入less.js前先引入。
备注:请在服务器环境下使用!本地直接打开可能会报错!

监视模式
监视模式是客户端的一个功能,这个功能允许你当你改变样式的时候,客户端将自动刷新。

要使用它,只要在URL后面加上'#!watch',然后刷新页面就可以了。另外,你也可以通过在终端运行less.watch()来启动监视模式。

在服务器端使用

安装

在服务器端安装 LESS 的最简单方式就是通过 npm(node 的包管理器), 像这样:
$ npm install less
如果你想下载最新稳定版本的 LESS,可以尝试像下面这样操作:
$ npm install less@latest

使用

只要安装了 LESS,就可以在Node中像这样调用编译器:

var less = require('less');

less.render('.class { width: 1 + 1 }', function (e, css) {
    console.log(css);
});

输出:

.class {
  width: 2;
}

你也可以手动调用解析器和编译器:

var parser = new(less.Parser);

parser.parse('.class { width: 1 + 1 }', function (err, tree) {
    if (err) { return console.error(err) }
    console.log(tree.toCSS());
});
配置

你可以向解析器传递参数:

var parser = new(less.Parser)({
    paths: ['.', './lib'], // 指定搜索路径
    filename: 'style.less' // 指定文件名
});

parser.parse('.class { width: 1 + 1 }', function (e, tree) {
    tree.toCSS({ compress: true }); // CSS输出
});
在命令行下使用

你可以在终端调用 LESS 解析器:
$ lessc styles.less
上面的命令会将编译后的 CSS 传递给 stdout, 你可以将它保存到一个文件中:
$ lessc styles.less > styles.css
// 如何你想将编译后的 CSS 压缩掉,那么加一个 -x 参数就可以了.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 模块的写法 一、原始写法 二、对象写法 上面的函数m1()和m2(),都封装在module1对象里。使用的时候,就...
    Dabao123阅读 1,797评论 1 0
  • 1.几种基本数据类型?复杂数据类型?值类型和引用数据类型?堆栈数据结构? 基本数据类型:Undefined、Nul...
    极乐君阅读 5,503评论 0 106
  • Why do you think learning english would be Useful? For me...
    曼步阅读 734评论 0 0
  • 当人在满足基本的物质生活需求后,灵魂变出来作祟了。不安分的躁动着,不想一成不变的按部就班;想要闹腾,想要折腾自己,...
    绿萝卜洛阅读 296评论 0 0
  • 不知道上次好好写字是什么时候了,反正是很久很久以前了。这几年升职加薪结婚生孩子以为过了很久,但一转眼一回头发现,那...
    Laura_LR阅读 237评论 0 0