• Less学习笔记


    镇楼图

    Pixiv:战争子

    注:此blog至少建立在一定的CSS基础之上,其中选择器更加重要



    〇、LESS(Leaner Style Sheets)是什么?

    是CSS的预处理器,因为CSS编写起来确实特别麻烦,因此有了CSS预处理器的工具来简化编写代码时间

    其他比较有名的CSS预处理还有SASS、SCSS、Stylus

    引入

    <link rel="stylesheet/less" href="styles.less" />
    <script src="//cdnjs.cloudflare.com/ajax/libs/less.js/3.11.1/less.min.js" ></script>
    <!-- 浏览器环境,引入Less.js,或者自己下载Less.js -->
    npm install -g less
    > lessc styles.less styles.css
    <!-- Node.js环境 -->
    

    由于LESS仅仅加了些许扩展,因此学习起来很简单,这也是为什么CSS的blog还没写完我先写LESS的情况。不必担心兼容性,LESS几乎支持一切浏览器

    问题一:如果在客户端环境下使用或多或少必然会有一定上性能的消耗

    问题二:LESS由于使用了Ajax必须必须在http(s)协议下使用,直接本地文件执行js文件是不会有任何效果的!!!!!

    Koala

    可以下载Koala用于将Less文件转译成css文件,由此可以使用生成的css文件而不必使用less文件也能避免上述所说的问题

    但是需要注意LESS在Koala里的版本是非常低的,为了避免因版本导致的错误,建议您安装nodejs后安装less,具体安装步骤这里就不再阐述了

    LESS文件编写

    首先创建个less后缀的文件,然后和CSS一样就可以开始写LESS加持的代码了

    但需要注意每个.less文件是独立编译的,其中的任何定义的东西都是不可相互访问的,也就是1.less中定义的变量不可以在2.less中访问


    一、变量

    尽管在CSS3中也存在变量机制,但其支持可能并不如LESS

    变量定义属性值

    变量可以去定义属性值,以【@变量名】的形式定义,调用属性值也是【@变量名】

    @ 10px;
    @height: 50px;
    
    .father {
         @width;
        height: @height;
    }
    

    个人理解:@指针

    变量本身是通过@去定义的,其中@可以理解为指针

    对上一个例子稍加改动可以很直观地说明这个问题

    @ 10px;
    @height: 50px;
    
    .father {
         width;
        height: @height;
    }
    

    当我用koala编译后它的结果如下图

    其中加了@的被解成了50px,没加@的就是其原样

    在下面变量定义变量能感受这种类似于指针的用法

    指针与变量赋值

    变量同样可以作为其他变量的变量

    @color1: grey;
    @color3: color1;
    //不加@就是其本身
    
    p{
        color: @@color3;
        //color3就是color3
        //@color3被解成了color1
        //@@color3被解成了grey
    }
    

    但是LESS似乎只支持到两层@,当博主尝试@@@时报错了

    在理解变量的本质后应该知道如何去赋值变量

    @color1: grey;
    @color3: @color1;
    //加@就是其属性值从而完成赋值操作
    
    p{
        color: @color3;
    }
    

    个人理解:$解引用(v3.0.0)

    在新版本3.0.0下可以使用$符号来解引用一个要作为样式的属性

    在某些情况下可能更加节省代码量。

    我个人认为这种语法适用于“同类属性”的情况,所谓同类属性是指功能性一样但应用范围不同,如下例的color、background-color都是用于颜色设置只不过一个是文字一个是背景罢了

    div {
        margin: 0px;
        padding: $margin;
        color: #fff;
        background-color: $color;
        //解引用无需定义新的变量
    }
    

    基于上面@假设为指针的理解,这里我理解为解引用,但理解归理解,实际操作和之前指针一样无法实现理解上的语法

    变量定义属性名和部分属性名(v1.6.0)

    除了属性值以外变量还可以定义很多内容,其中只要不是去定义属性值或是变量的,在调用时必须以【@{变量名}】的形式去调用

    LESS不像正统语言一样有严格的语法规范,有些看上去可能符合猜想的语法都会报错

    @p1: color;
    
    .father {
        @{p1}: red;
    }
    

    此外还可以去定义部分属性名,很多CSS属性会用-符号区分这时候可以通过LESS这样定义

    @v: left;
    
    .div1 {
        margin-@{v}: 0;
    }
    

    变量定义选择器(V1.4.0)

    @firbox: father;
    @element: a;
    
    .@{firbox} > @{element}[data-v="1"]:visited {
    	color: red;
    }
    

    变量定义url(的一部分)(v1.4.0)

    由于url网址部分一般都是会有相同的前缀部分,也可以定义url字符串在url里使用

    @images: "../images";
    
    html {
        background: url("@{images}/1.jpg");
    }
    

    变量作用域(Lazy evaluation)

    只要保证调用变量时能从当前层级往上能找到即可

    @{selector} {
        @{attr}: @value;
        @value: red;
    }
    @attr: color;
    @selector: p;
    //虽然定义在下
    //但能从调用处往上寻找时能搜查到此层级
    

    另外这种搜查机制也对于同名变量来说符合就近原则

    p {
        @v: #123;
    	color: @v;
        @v: #456;
        //结果为#456
        //它会优先搜查一遍
        //搜查后#456当然覆盖了#123
    }
    @v: #789;
    //由于调用那一层已经搜查到了
    //因此无需向上搜查此层
    

    二、属性值运算

    赋值

    上面有讲过便不再赘述

    @a: 10;
    @b: @a;
    

    空格附加

    比如CSS中margin多个属性值来说是通过空格来间隔开的,LESS提供这样一个机制去实现多个属性值空格相加

    通过+_符号以空格形式附加属性值

    @v1: 10px;
    @v2: 20px;
    @v3: 30px;
    @v4: 40px;
    .div1{
        /*已忽略其他必要属性*/
        margin+_: @v1;
        margin+_: @v2;
        margin+_: @v3;
        margin+_: @v4;
    }
    
    .div2{
    	margin: @v1 @v2 @v3 @v4;
        //虽然也能通过这种方式附加
        //这与后面的函数相关联
        //比如设定一个函数附加属性值
        //这样的机制无法实现而+_可以
    }
    

    逗号附加

    还有一类属性值必须要通过逗号隔开,LESS是通过+符号以逗号形式附加属性值

    这里不作演示了

    简单运算

    对于Less而言它可以进行一些简单的运算,当然在Less内置函数中还内置大量数学函数可以实现非常复杂的运算

    @size: 10;
    @o1: @size + 5;
    @o2: @size - 5;
    @o3: @size * 5;
    
    div {
    	d1: @o1;
    	d2: @o2;
    	d3: @o3;
    }
    

    三、嵌套(Nesting)

    嵌套

    嵌套是非常常用的工具,可以使大量CSS难以看清楚的结构,在Less中变得显而易见

    father {
        display: flow-root;
        .first,.second {
             400px;
            height: 200px;
        }
        .first {
            margin-bottom: 100px;
            background: purple;
        }
        .second {
            margin-top: 200px;
            background: green;
        }
    }
    //比如这里显而易见的,father中套了first、second
    //而CSS处理的话只会分开,当数量足够多时便很难分清结构了
    

    引用父元素

    嵌套虽然实现了父类→子类的,但无法实现子类→父类,&提供了从子类→父类的功能

    这一般用于类、复杂运算、属性值选择器或是伪类,如下例只需要&即可实现不同伪类的情况,同样其结构也更加清晰

    a {
        font-size: 20px;
        background: pink;
        &:link {
            color: red;
        }
        &:visited {
            color: green;
        }
        &:active {
            color: hotpink;
        }
        &:hover {
            color: blue;
        }
    }
    

    所谓引用是真的完全引用,不会有太大的语法限制

    也会有这种形式的LESS代码

    .area {
        &-1 {}
        &-2 {}
        //类
        & &[data-v1="3"]:hover{}
        .father &{}
        //假设.father盒子嵌套.area盒子
        //那么可以实现这种嵌套的样式
        //复杂运算
    }
    //通过这种方式可以很好地集成代码
    

    你可能会担心还会生成一个.area的父类,但实际上LESS会进行优化,只要你的选择里没有任何样式那么它就不会生成此类。.area下面全都是选择器,并不是具体的样式,因此它不会生成.area这一个父类,可以放心大胆地使用这种代码

    引用父元素的组合

    上面阐述了引用父元素下其子元素能够如何如何之类的,但是其父元素也是可以参与运算的,这样会导致更加灵活的嵌套,但目前我个人没找到这种实际应用的场景

    .a,.b > .c{
        & & {}
    }
    

    因为CSS除了组合运算以外不管是伪类也好属性选择器也好,它本质上都只是一个选择器,但组合选择器是多个。

    核心在于组合运算,上面例子仅仅是组合了.a和.b > .c两个选择器,使用& &{}会是什么?

    LESS会把每一个&尝试组合中的所有选择器

    结果会是

    .a .a,
    .a .b > .c,
    .b > .c .a,
    .b > .c .b > .c {
    	/*某个样式*/
    }
    

    这里简单用数学计算下,假设LESS代码里定义选择器时有n个&符号,而父类组合的有m个选择器,那么其组合后总共会去组合\(m^n\)个选择器


    四、混合(Mixins)

    函数

    这里博主统一称为函数,一个样式规则集可以当作函数。函数内部可以写好一个样式模板,某个属性需要时调用即可

    但是需要注意函数的命名必须是类选择器或是id选择器的命名

    .a , #b {
        //既可以当作某个样式渲染(如果HTML中满足的话)
        //也可以当作函数来调用
        color: red;
        font-size: 19px;
    }
    
    .father {
        #b();
    }
    

    由于版本原因,调用的时候()是可选的,在未来版本可能会被删除

    .a , #b {
        color: red;
        font-size: 19px;
    }
    
    .father {
        .a;
    	//不用()也能生效
    }
    

    参数

    上面的语法也会当作样式来渲染,但有时候可能就想当作函数,这时候只需要在函数后加上()即可

    .c() {
        //不会生成.c的CSS代码
        color: red;
        &:link {
            color: red;
        }
        &:visited {
            color: green;
        }
        &:active {
            color: hotpink;
        }
        &:hover {
            color: blue;
        }
    }
    
    a {
        .c;//此时&引用是a
    }
    

    此外可以设置形参来传递实现更复杂的操作

    .color(@color){
        color: @color;
    }
    .fontsize(@size: 16px){
        //可以设置默认值
        font-size: @size;
    }
    
    p {
        .color(black);
        //未设置默认值必须填写参数
    	.fontsize();
    }
    

    在写默认值有时并不止一个属性值

    如果多个属性值是要用,分隔的,此时可以用;分隔参数

    如果多个属性值是用空格分隔的,可以用,也可以用;分隔参数

    .a(@border:3px solid red ; @margin:0 auto){
        //用;分隔参数
    	border: @border;
    	margin: @margin;
    }
    
    div {
    	.a;
    }
    

    调用参数时可以指定形参名,这时调用无需注意顺序

    .a(@border:3px solid red;@margin:0 auto){
      border: @border;
      margin: @margin;
    }
    div{
      .a(@margin:10%);
    }
    

    函数的嵌套

    由于嵌套语法的存在,函数也是可以嵌套的

    LESS提供了三种等价性的调用方式

    分别是.father > .son,.father .son和.father.son

    这三种形式没有任何区别,它会调用所有下一级子函数的样式

    .a(){
        color:blue;
        font-size: 18px;
        .b(){
            padding: 0;
            color:red;
            .b(){
                margin: 0;
            }
        }
        .b(){
            background: black;
            color:blue;
            //LESS输出并不会去覆盖样式
            //因此结果里会有两个color
        }
    }
    
    .div1 {
    	.a.b;
    }
    
    .div2 {
    	.a > .b .b();
    }
    

    调用的函数只会在这一层而不会出现其父类或是子类的函数,若要使用子类的函数必须去调用才行

    守卫(Guard)

    在LESS中when的保护条件称为是Guard,其中只有满足when条件才可执行,不满足不会被执行

    .a() when(true){
    	color: red;
    }
    p {
        .a;
    }
    
    .b() when (@mode = 1){
    	color: blue;
    }
    p {
        @mode: 2;
        .b;
        //@mode为2不满足
        //因此会拒绝.b()函数调用
    }
    

    在1.5以后守卫机制不仅可以适用于函数还可以适用于选择器上

    @my-option: true;
    & when (@my-option = true) {
        //备注:若不存在&则不会有父元素
        //但可以用不存在的元素专门用作条件语句
      	button {
        	color: white;
      	}
      	a {
        	color: blue;
      	}
    }
    

    @arguments

    @arguments可以将所有参数同时传递

    .pos(@top: 0; @right: 0; @bottom: 0; @left: 0) {
    	margin: @arguments;
    	padding: @arguments;
        //同时传递了@top @right @bottom @left
        //且参数之间是空格附加的
    }
    div {
    	.pos(50px,30px,50px,20px);
    }
    

    @rest以及不定参数

    用...可以表示不定参数,@rest可以指定剩余的可变参数

    但CSS的属性值绝大部分都是有限个,因此应用场景可能不多

    .minin()){}//无参
    .minin(@rest...){}//任意个参数
    .minin(@a){}//无参或一个参数
    .minin(@a;@rest...){}//任意个参数
    .minin(@a: 1;@rest...){}//至少一个参数
    

    模式匹配

    LESS的函数是只要满足就会实现,因此可以设定一个常量作为形参

    当满足该常量时便会执行,否则不会执行,可以作为不同情况的函数

    .mixin(dark; @color) {
      color: darken(@color, 10%);
    }
    .mixin(light; @color) {
      color: lighten(@color, 10%);
    }
    
    div {
      .mixin(light, #888);
       .mixin(dark,#aaa);
        //执行drak的.mixin函数
    }
    

    实现分支结构

    LESS中是通过保护条件来实现分支语句的,如下面实现采用更大宽度的代码

    .max(@a; @b) when (@a > @b) {  @a }
    .max(@a; @b) when (@a < @b) {  @b }
    

    此外条件之间也可以使用and、or、not这三类逻辑运算符

    对于函数的返回值博主认为应用场景不多故此忽略,详细可在官网中查看器语法

    至于循环结构博主认为只需要在第六节提到的each方法即可实现,无需本身的循环结构

    实现哈希表(v3.5.0)

    在3.5.0的版本中变量可以去存储函数,基于这个机制可以实现哈希表

    #Font(){
        //定义#Font实例内置size、color数据
        .size(){
            style1: 12px;
            style2: 15px;
            style3: 18px;
        }
        .color(){
            style1: black;
            style2: white;
            style3: grey;
        }
    }
    
    p{
    	@f-c: #Font.color();
        color: @f-c[style1];
    	font-size: #Font.size()[style3];
    	//可以直接通过函数去索引相当于哈希表
    }
    

    选择器、属性名作为参数

    我之前用less确确实实有这么一个需求,需要针对不同类名某些相同属性设定不同的属性值,那么可以如下实现

    .f(@selector,@value){
        //@selector作为类选择器参数
        .@{selector} {
            font-size: @value;
        }
    }
    .f(m1,12px);
    .f(m2,14px);
    .f(m3,16px);
    

    此时可以将选择器作为一个形参来设置属性值,属性名同理这里不再赘述

    函数作为参数

    函数本身也是可以作为形参对象的,这在封装某些代码时会非常有用

    .media(@rules1,@rules2) {
    	@media screen and (max- 799px) {
    		@rules1()
    	}
      	@media screen and (min- 800px)  {
          	@rules2();
      	}
    }
    .f(){
    	font-size: 18px;
    }
    .g(){
    	font-size: 24px;
    }
    * {
    	.media(.f(),.g());
        //备注:必须加()否则出错
    }
    

    五、扩展(Extend)

    Less中有一个特殊的伪类——extend,它用于实现组合运算

    因为有时仅仅是嵌套,混合并不能完全满足开发需求,扩展适用于选择器组合运算时的某些相同样式

    extend伪类

    下例将会先生成nav选择器,再生成nav, .inline选择器

    nav {
      &:extend(.inline);
      background: blue;
    }
    .inline {
      color: red;
    }
    

    extend内同样可以有多个选择器的组合形式

    .div1:extend(.f, .g) {}
    //extend参数组合等价于下面两行语句
    
    .div1:extend(.f) {}
    .div1:extend(.g) {}
    //LESS允许多个extend但效果仍然是组合
    //下面的代码与上面的是等价的
    .div1 :extend(.f) :extend(.g) {}
    //备注:extend允许与选择器之间存在空格
    

    同样地除了内部参数的组合还可以有父选择器的组合

    pre:hover, .some-class {
      &:extend(div pre);
    }
    //等价于如下代码
    pre:hover:extend(div pre),
    .some-class:extend(div pre) {}
    

    extend伪类可能会与其他伪类相互结合,但LESS的extend伪类必须位于最后,否则报错

    pre:hover:extend(div pre).nth-child(odd) {}
    //报错,extend伪类必须位于最后
    

    精确匹配

    extend内的选择器是精确匹配的,附加任何运算形式都不会计算在内

    *.class {
      	color: blue;
    }
    .noStar:extend(.class) {
        //不存在.class选择器
        //不会有任何组合效果
        color: red;
    } 
    

    all选项

    扩展虽然是精确匹配的,但all参数可以解除这种精确性

    使用all参数匹配会改成匹配有关参数的所有选择器,并且会进行相同的运算

    .div:extend(.other all) {
        //组合有关.other的所有选择器
    	//且会进行相同运算的组合
    }
    .other {
        //会去精确匹配
    	color: blue;
    }
    *.other {
        //附上了运算
        //得到的组合会是*.div, *.other
    	margin: 0 auto;
    }
    .other > .e {
        //同理组合是.div > .e, .other > .e
    	padding: 0;
    }
    .father{
        //同理组合是.father .div,.father .other
    	border-style: dashed;
    	.other {
    		overflow: hidden;
    	}
    }
    .other {
    	//同理组合是.div .sub,.other .sub
    	clear: left;
    	.sub {
    		display: flow-root;
    	}
    }
    

    缺陷

    目前extend组合语法并不支持在参数内使用变量,因为语法角度来说是有可能会用到extend内为变量去动态地组合

    但是外部的选择器是可以使用变量替代的

    .bucket {
      color: blue;
    }
    @{variable}:extend(.bucket) {}
    @variable: .selector;
    

    六、其他

    @import声明(1.4.0)

    与CSS不同的是Less的@import可以随意在任意地方声明

    Less可以去调用其他样式文件,调用后其文档原本全局变量的作用域会改成当前文档

    @pref: "../lessheader";
    
    p {
        font-size: @size2;
    }
    
    @import "@{pref}/header1.less"
    /*假设@size2在header1.less中
      这里提供了一种类似于头文件的声明方式
      可以去管理Less的变量、函数
    */
    

    还有其他一部分内容,但属于提高less的可扩展性,这里就不做过多介绍了

    数学函数

    备注:CSS有单位一说,但大部分数学函数转换后依然是原本单位

    函数 说明
    pi() 返回圆周率π
    abs(x) x取绝对值
    ceil(x) 对x上取整
    floor(x) 对x下取整
    percentage(x) 将x转成百分数,如0.15转成15%
    round(x,decimal) 对x第decimal位四舍五入
    decimal可省略默认为0即整数四舍五入
    如round(1.8877,2)会返回1.89
    mod(a, b) 返回a%b
    sqrt(x) x取根号
    pow(base, exp) 返回base的exp方
    sin(x),cos(x),tan(x) 三角函数,详细见备注
    asin(x),acos(x),acot(x) 反三角函数,详细见备注
    min(v1,...),max(v1,...) 至少输入1个参数,返回最小/大值

    备注:LESS对三角函数支持三类单位,分别是弧度制、角度制、百分度制,但返回值统一是弧度制

    sin(2);//弧度制
    cos(60deg);//角度制
    tan(100grad);//百分度制
    

    布尔值

    Less以函数形式支持boolean数据类型

    创建条件如下

    @flag: boolean(/*条件*/@a > 5);
    @a: 10;
    

    if函数

    虽然有guard机制实现分支,但也以函数形式提供了分支语句

    格式为【if(条件,true时执行语句,false时执行语句)】

    其中可以忽略最后的false时执行的语句

    若要实现if-else的结构需要在false处再嵌套if语句

    @bg: black;
    @bg-light: boolean(luma(@bg) > 50%);
    
    div {
      background: @bg; 
      color: if(@bg-light, black, white);
    }
    

    字符串常用函数

    函数 说明
    e(str) 删除str的分号
    如具体处理时采用字符串
    但调用却不是字符串那么可以使用此方法
    %(str,arg,...) 格式化字符串,详细见备注

    备注:可以使用%函数来格式化字符串,其中占位符有分大小写,其中小写会保持特殊字符的原样,而大写会将特殊字符转成UTF-8编码形式,如空格会转成%20,/会转成%2

    由于使用了%表示占位符,若要表示%本身需要写成%%

    占位符 说明
    %a,%A,%d,%D 与其他语言不同
    它可以被任何类型替代而不是专指某类数据类型
    %s,%S 上一方式在表达字符串时存在问题
    它会将表述字符串的引号
    使用这一类占位符可以忽略字符串的引号
    format-a-d-upper: %('repetitions: %A file: %d', 1 + 2, "directory/file.less");
    //存在问题,由于不是%s会带来引号
    

    数组

    Less支持一个变量去定义数组,在某些情况可能有较好的效果

    比如设计网站后将所有会用到的颜色集成一个数组

    @Color: "white" "grey" "green";
    //用逗号分隔或空格分隔即可定义数组
    //但需要统一分隔符,除非属性值的表述需要分隔符
    
    数组相关函数 说明 版本说明
    length(arr) 返回数组元素个数
    extract(arr, index) 索引,返回arr第index个元素
    备注:下标从1开始
    range(start,end,step) 详细见下节内容 v3.9.0
    each(arr, rules) 详细见下节内容 v3.7.0
    @Color: "white" "grey" "green";
    p {
        color: extract(@Color,2);
        //设置为灰色,但这里存在些问题
    }
    

    高版本功能:实现循环结构(v3.9.0)

    数组新方法特别好用,蓝桥杯web比赛的less只支持到2.x的版本可惜了

    range函数用于生成数组,each用做循环

    range(2,5,2);//返回数组元素2 4
    range(3);
    //也可以省略初值和步长,默认为1
    //返回数组1 2 3
    

    each函数用来迭代

    each(@selector, {
        @{selector}{
            margin: 0 auto;
        }
    });
    //第一个参数为数组
    //第二个参数为函数可以匿名定义
    

    解析获取属性值

    Less提供了一类函数可以通过某些值来获取相应属性值,比如只要知道图像的url就可以获取其大小

    函数 说明 版本说明
    color(str) 字符串转成颜色值
    image-size(str) 根据字符串表述的url返回相应文件的大小
    备注:同时返回宽度和高度可以用数组来接收
    2.2.0
    image-widtht(str) 同上但只返回宽度 2.2.0
    image-height(str) 同上但只返回高度 2.2.0
    unit(number,unit) ①若省略unit作用是返回其不带单位的数字本身,在运算上不会出现混乱,如unit(1000ms)返回为1000
    ②不省略unit则会去设置单位,不管原本number有没有单位都会替换,如unit(10px,cm)返回10cm
    get-unit(number) 返回number的单位,若无单位不会返回任何内容
    该函数可以结合unit进行较灵活的单位转换
    convert(number,unit) 将number的单位及数值进行等价替换
    unit纯粹是改变单位,但convert还会换算数值
    convert限定了必须在某一组单位进行转换否则不会产生任何效果
    ①长度:m, cm, mm, in, pt, pc
    ②s, ms
    ③角度:rad, deg, grad, turn
    convert(9s, "ms");
    //在时间组内等价替换成9000ms
    
    @Color: "white" "grey" "green";
    p {
        color: color(extract(@Color,2));
        //直接从数组获取字符串但它并不是颜色值
        //通过color函数转成可用的颜色值
    }
    

    判定类型

    Less提供一组函数用于判定不同的数据类型

    函数 说明
    isnumber(x) 判定是否为数值
    isstring(x) 判定是否为字符串
    iscolor(x) 判定是否为颜色值
    isurl(x) 判断是否为url
    ispixel(x) 判断其单位是否为px
    isem(x) 判断其单位是否为em
    ispercentage(x) 判断其单位是否为%
    isunit(x,unit) 判断其单位是否为unit
    isruleset(x) 判断是否为规则集
    由于变量可以表述任何内容
    导致有时并不能直接看出一个变量代表着什么

    备注:严格来说上面的函数准确名字叫做规则集,函数是指带返回值的

    但这里博主自作主张地称其为函数



    参考教程

    LESS

    尚硅谷

  • 相关阅读:
    jQuery获取鼠标事件源
    windows中MongoDB安装和环境搭建
    前端获取后台数据的方法:ajax、axios、fetch
    浅谈:easy-mock的使用
    安全篇-AES/RSA加密机制
    PHP开发api接口安全验证
    Ajax简单实现文件异步上传的多种方法
    PHP7有没有你们说的那么牛逼
    基于laravel框架构建最小内容管理系统
    redis用法分析
  • 原文地址:https://www.cnblogs.com/AlienfronNova/p/16244911.html
Copyright © 2020-2023  润新知