预处理器 Less 的十个语法

Posted 一颗冰淇淋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了预处理器 Less 的十个语法相关的知识,希望对你有一定的参考价值。

Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量、混合(mixin)、函数等功能,让 CSS 更易维护、方便制作主题、扩充。

不过浏览器只能识别 CSS 语言,所以 Less 语言直接运行在浏览器端是不被识别的,需要我们通过一些方式将其先转成 CSS,再将 CSS 资源加载到浏览器中。

如何转换

根据使用场景不同,我们可以分别采用包管理工具/CDN资源的形式。

包管理工具

nodejs + webpack
在工程化项目中,我们使用 webpack 来对项目进行编译时,可以在 module 中定义处理 Less 资源的方式,本质上是使用 Less 工具来对 Less 资源进行转换,但 webpack 中是使用对应的 loader 来处理(需要安装 less、less-loader)。

nodejs + gulp
gulp 以流的形式执行定义的任务,它处理 Less 资源除了 less 工具,还需要安装 gulp-less 。

nodejs + vite
vite 中不需要多做任何配置,只需安装 less 工具。

CDN资源

当不适合使用包管理工具时,可以直接引入CDN的LESS编译代码,对LESS进行实时的处理。

<link rel="stylesheet/less" href="./basic.less"> 
<script src="https://cdn.jsdelivr.net/npm/less@4"></script>

这里需注意的是,link标签定义的 rel 需要是 stylesheet/less,这样后面的js资源才会将Less语法处理成CSS。

  • rel=“stylesheet”,会主动发送http请求获取css资源
  • rel=“stylesheet/less”,不会发送http请求
  • rel=“stylesheet/less” + 处理less的js资源,先请求js文件,再发送获取stylesheet的css资源

Less转CSS预览

官方提供了可在线预览Less转CSS代码的工具(Less-preview),在这里可以看到每个语法到底做了怎样的转化,了解后更能按照自己所需要的场景选择。

语法

有了Less资源的处理工具后,可以开始放心大胆的编写Less语法啦~

一、兼容css
Less 是完全兼容 CSS 的,所有 CSS 代码都可以编写,导入的方式和 CSS 的用法是一致的,导入一个 .less 文件,此文件中的所有变量就可以全部使用,如果导入的文件是 .less 扩展名,则可以将扩展名省略掉。

二、使用变量
有些常用的主题色、字体,我们可能会使用一个固定的类名,当需要使用的时候在标签上叠加类名,这样使得类名很多,通过变量的形式,无需再多次添加类。

三、嵌套
CSS 中语法不能嵌套,为了保证代码的可阅读性,我们需要按照一定的顺序将样式依次从父元素定义到子元素,但在 Less 中就没有这个困扰,像层层包裹的形式来书写,可以清晰的看到父子级关系。

四、运算
运算这个功能不算好用,并不会像函数一样,比较“智能”的转换成我们需要的结果,比如设置高度,它没有进行单位转换,只是保留第一位的单位,再简单的加减乘除。

五、混入/混合
混入/混合 可以将多个css属性合成一组值(比如设置一行展示,超出长度显示省略号的样式),插入到其它选择器中。通过选择器加上小括号的形式使用,括号内也可以接受参数。

Less编写看起来是代码量变多,但使用起来却是更加灵活,能将它作为一个组合来使用,随意放置到所需要的地方。

六、映射
将混合、映射结合起来使用,可以弥补Less中不能自定义函数的缺陷,比如可以获取混入中定义的宽度,定义px转换rem的函数。

七、继承
语法:&:extend(选择器),生成的代码与混入不同,混入是直接将代码加到后面,继承用的是并集选择器。

开发中用混入更多,因为混入更灵活、语法更简洁、直接插入后面生成的css语法阅读性更强。

八、内置函数
除了 CSS 本身就有的 linear-gradient、calc、rgba,Less 还拓展了一些函数,比如颜色转换 color,数组取值 extract,条件判断 if,向上取整 ceil。

九、作用域
在查找一个变量时,首先在本地查找变量和混合, 如果找不到,则从“父”级作用域继承。

十、注释
在css中,只能使用块注释,在Less中,块注释和行注释都可以使用。

以上就是 Less语法的介绍, 通过 Less,我们可以编写出更优雅、可读性更强、更易维护的 CSS 代码。下一篇将介绍 SASS的相关使用,更多有关 前端CSSjavascript的内容可以参考我其它的博文,持续更新中~

Java 日期处理易踩的十个坑

前言


整理了 Java 日期处理的十个坑,希望对大家有帮助。


1. 用 Calendar 设置时间的坑


反例:


Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR, 10);
System.out.println(c.getTime());

运行结果:

Thu Mar 26 22:28:05 GMT+08:00

解析:

我们设置了 10 小时,但运行结果是 22 点,而不是 10 点。因为 Calendar.HOUR 默认是按 12 小时制处理的,需要使用 Calendar.HOUR_OF_DAY,因为它才是按 24 小时处理的。

正例:

Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 10);


2. Java 日期格式化 YYYY 的坑

反例:


Calendar calendar = Calendar.getInstance();
calendar.set(2019, Calendar.DECEMBER, 31);
Date testDate = calendar.getTime();
SimpleDateFormat dtf = new SimpleDateFormat("YYYY-MM-dd");
System.out.println("2019-12-31 转 YYYY-MM-dd 格式后 " + dtf.format(testDate));

运行结果:

2019-12-31 转 YYYY-MM-dd 格式后 2020-12-31

解析:

为什么明明是 2019 年 12 月 31 号,就转了一下格式,就变成了 2020 年 12 月 31 号了?因为 YYYY 是基于周来计算年的,它指向当天所在周属于的年份,一周从周日开始算起,周六结束,只要本周跨年,那么这一周就算下一年的了。正确姿势是使用 yyyy 格式。

正例:

Calendar calendar = Calendar.getInstance();
calendar.set(2019, Calendar.DECEMBER, 31);Date testDate = calendar.getTime();SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd");
System.out.println("2019-12-31 转 yyyy-MM-dd 格式后 " + dtf.format(testDate));

3. Java日期格式化hh的坑。

反例:


String str = "2020-03-18 12:00";SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd hh:mm");Date newDate = dtf.parse(str);
System.out.println(newDate);

运行结果:

Wed Mar 18 00:00:00 GMT+08:00

解析:

设置的时间是 12 点,为什么运行结果是 0 点呢?因为 hh 是 12 制的日期格式,当时间为 12 点,会处理为 0 点。正确姿势是使用 HH,它才是 24 小时制。

正例:


String str = "2020-03-18 12:00";SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
Date newDate = dtf.parse(str);
System.out.println(newDate);

反例:


//获取当前月,当前是3月Calendar calendar = Calendar.getInstance();
System.out.println("当前"+calendar.get(Calendar.MONTH)+"月份");

运行结果:

当前2月份

解析:The first month of the year in the Gregorian and Julian calendarsis JANUARY which is 0;

也就是1月对应的是下标 0,依次类推。因此获取正确月份需要加 1。

正例:


//获取当前月,当前是3月Calendar calendar = Calendar.getInstance();
System.out.println("当前"+(calendar.get(Calendar.MONTH)+1)+"月份")

5. Java 日期格式化 DD 的坑

反例:


Calendar calendar = Calendar.getInstance();
calendar.set(2019, Calendar.DECEMBER, 31);Date testDate = calendar.getTime();SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-DD");
System.out.println("2019-12-31 转 yyyy-MM-DD 格式后 " + dtf.format(testDate));

运行结果:

2019-12-31 转 yyyy-MM-DD 格式后 2019-12-365

解析:

DD 和 dd 表示的不一样,DD 表示的是一年中的第几天,而 dd 表示的是一月中的第几天,所以应该用的是 dd。

正例:


SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(sdf.format(20200323));

6. SimleDateFormat的format 初始化问题

反例:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");System.out.println(sdf.format(20200323));

运行结果:

1970-01-01

解析:

用 format 格式化日期是,要输入的是一个 Date 类型的日期,而不是一个整型或者字符串。

正例:


Calendar calendar = Calendar.getInstance();
calendar.set(2020, Calendar.MARCH, 23);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(sdf.format(calendar.getTime()));

7. 日期本地化问题

反例:


String dateStr = "Wed Mar 18 10:00:00 2020";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy");
LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);
System.out.println(dateTime);

运行结果:


Exception in thread "main" java.time.format.DateTimeParseException: Text Wed Mar 18 10:00:00 2020 could not be parsed at index 0
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949) at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851) at java.time.LocalDateTime.parse(LocalDateTime.java:492) at com.example.demo.SynchronizedTest.main(SynchronizedTest.java:19)

解析:

DateTimeFormatter 这个类默认进行本地化设置,如果默认是中文,解析英文字符串就会报异常。可以传入一个本地化参数(Locale.US)解决这个问题。

正例:


String dateStr = "Wed Mar 18 10:00:00 2020";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy",Locale.US);
LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);
System.out.println(dateTime);

8. SimpleDateFormat 解析的时间精度问题

反例:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String time = "2020-03";
System.out.println(sdf.parse(time));

运行结果:

Exception in thread "main" java.text.ParseException: Unparseable date: "2020-03"
at java.text.DateFormat.parse(DateFormat.java:366) at com.example.demo.SynchronizedTest.main(SynchronizedTest.java:19)

解析:

SimpleDateFormat 可以解析长于/等于它定义的时间精度,但是不能解析小于它定义的时间精度。

正例:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
String time = "2020-03";
System.out.println(sdf.parse(time));

9. SimpleDateFormat 的线性安全问题

反例:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches
public static void main(String args[])

// String to be scanned to find the pattern.
String line = "This order was placed for QT3000! OK?";
String pattern = "(.*)(\\\\d+)(.*)";

// Create a Pattern object
Pattern r = Pattern.compile(pattern);

// Now create matcher object.
Matcher m = r.matcher(line);
if (m.find())
System.out.println("Found value: " + m.group(0));
System.out.println("Found value: " + m.group(1));
System.out.println("Found value: " + m.group(2));
else
System.out.println("NO MATCH");


运行结果:


Exception in thread "pool-1-thread-49" java.lang.NumberFormatException: For input string: "5151."
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Long.parseLong(Long.java:589) at java.lang.Long.parseLong(Long.java:631) at java.text.DigitList.getLong(DigitList.java:195) at java.text.DecimalFormat.parse(DecimalFormat.java:2051) at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162) at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514) at java.text.DateFormat.parse(DateFormat.java:364) at com.example.demo.SimpleDateFormatTest.lambda$main$0(SimpleDateFormatTest.java:19) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)Exception in thread "pool-1-thread-47" java.lang.NumberFormatException: For input string: "5151."
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Long.parseLong(Long.java:589) at java.lang.Long.parseLong(Long.java:631) at java.text.DigitList.getLong(DigitList.java:195) at java.text.DecimalFormat.parse(DecimalFormat.java:2051) at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162) at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514) at java.text.DateFormat.parse(DateFormat.java:364) at com.example.demo.SimpleDateFormatTest.lambda$main$0(SimpleDateFormatTest.java:19) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)

解析:

全局变量的 SimpleDateFormat,在并发情况下,存在安全性问题。

  • SimpleDateFormat 继承了 DateFormat;
  • DateFormat 类中维护了一个全局的 Calendar 变量;
  • sdf.parse(dateStr) 和 sdf.format(date),都是由 Calendar 引用来储存的;
  • 如果 SimpleDateFormat 是 static 全局共享的,Calendar 引用也会被共享;
  • 又因为 Calendar 内部并没有线程安全机制,所以全局共享的 SimpleDateFormat 不是线性安全的。

解决 SimpleDateFormat 线性不安全问题,有三种方式:

  • 将 SimpleDateFormat 定义为局部变量;
  • 使用 ThreadLocal;
  • 方法加同步锁 synchronized。

正例:


public class SimpleDateFormatTest
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
private static ThreadLocal < DateFormat > threadLocal = new ThreadLocal < DateFormat > ();
public static DateFormat getDateFormat()
DateFormat df = threadLocal.get();
if (df == null)
df = new SimpleDateFormat(DATE_FORMAT);
threadLocal.set(df);

return df;

public static String formatDate(Date date) throws ParseException
return getDateFormat().format(date);

public static Date parse(String strDate) throws ParseException
return getDateFormat().parse(strDate);

public static void main(String[] args)
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue < > (1000));
while (true)
threadPoolExecutor.execute(() - >
try
String dateString = formatDate(new Date());
Date parseDate = parse(dateString);
String dateString2 = formatDate(parseDate);
System.out.println(dateString.equals(dateString2));
catch (ParseException e)
e.printStackTrace();

);


10. Java日期的夏令时问题

反例:


TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.parse("1986-05-04 00:30:00"));

运行结果:

Sun May 04 01:30:00 CDT 1986

解析:

先了解一下夏令时:

夏令时,表示为了节约能源,人为规定时间的意思。一般在天亮早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏时制的国家具体规定不同。目前全世界有近110个国家每年要实行夏令时。

1986年4月,中国中央有关部门发出“在全国范围内实行夏时制的通知”,具体作法是:每年从四月中旬第一个星期日的凌晨2时整(北京时间),将时钟拨快一小时。(1992年起,夏令时暂停实行。)

夏时令这几个时间可以注意一下哈,1986-05-04, 1987-04-12, 1988-04-10, 1989-04-16, 1990-04-15, 1991-04-14.

结合 Demo 代码,中国在 1986-05-04 当天还在使用夏令时,时间被拨快了 1 个小时。所以 0 点 30 分打印成了 1 点 30 分。如果要打印正确的时间,可以考虑修改时区为东 8 区。

正例:

TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.parse("1986-05-04 00:30:00"));

以上是关于预处理器 Less 的十个语法的主要内容,如果未能解决你的问题,请参考以下文章

CSS预处理器之Less详解

Sass和Less

Web前端之less简介

前端less学习

H5前端学习之路第1天--css预处理器

CSS预处理——LESS