less,sass,stylus配置和应用教程及三者比较
2014-09-06 23:22 龙恩0707 阅读(3203) 评论(1) 编辑 收藏 举报less,sass,stylus配置和应用教程及三者比较
Less
1. 定义:
Less是CSS预处理语言,在css基础之上增加了诸如变量,混合(mix),继承,运算,函数等功能,LESS既可以运行在客户端(支持IE10+,firefox,Webkit),也可以借助于Node.js在服务器端运行(支持IE6+,firefox,Webkit)。
什么是CSS预处理技术?CSS预处理技术,是指用一种新语言用来为CSS 增加可编程的的特性,无需考虑浏览器的兼容性问题。你可以在 CSS 中使用变量、简单的程序逻辑、函数等等在编程语言中的一些基本技巧,可以让你的 CSS 更见简洁,适应性更强。支持多样性的CSS语法.
2. 配置教程(如何使用)。
1.客户端使用Less文件:
客户端使用less文件很简单,只需要引用less.js即可(下面是线上cdn的less.js):如下在页面上这样引用。
<link rel="stylesheet/less" type="text/css" href="styles.less" />
<script src="http://cdn.bootcss.com/less.js/1.7.0/less.min.js"></script>
注意: 上面的less文件 是我们自己写的less样式文件,且一定要放在less.js之前,这样才可以正确的被解析成正常的css样式。且经过测试使用客户端这样引用在IE6-9并不生效,也就是说并没有和网上说的一样能正确被解析css样式,所以我们不建议用客户端这样引用。
下面我们先来看看Less的变量,混合,继承,运算,函数等功能的demo。
1. 变量:
变量允许我们单独定于一系列通用的样式,然后在需要的时候去调用他。如下代码:
// LESS @color: #4D926F; #header { color: @color; } h2 { color: @color; }
在浏览器预览,他会被正确的解析成如下css样式:
/* 生成的 CSS */ #header { color: #4D926F; } h2 { color: #4D926F; }
也就是说我们可以用javascript语言来这样理解,@color可以作为一个全局变量,然后在各个函数里面我们想使用它,可以直接调用它。
2.混合:
混合可以将一个已定义好的classA轻松引入到classB中,从而简单的实现classB继承与classA中的所有属性。我们也可以带参数地调用,就像使用函数一样。如下代码:
// LESS .rounded-corners (@radius: 5px) { border-radius: @radius; -webkit-border-radius: @radius; -moz-border-radius: @radius; } #header { .rounded-corners; } #footer{ .rounded-corners(10px); }
在css中会被解析成如下代码
/* 生成的 CSS */ #header { border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px; } #footer { border-radius: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; }
3.嵌套规则:
我们可以在一个选择器中嵌套另一个选择器来实现继承,这样很大程度上减少了代码量,并且代码看起来更加清晰。如下代码演示被解析成css后的样式:
// LESS #header { h1 { font-size: 26px; font-weight: bold; } p { font-size: 12px; a { text-decoration: none; &:hover { border-width: 1px } } } }
被生成css文件如下样式:
/* 生成的 CSS */ #header h1 { font-size: 26px; font-weight: bold; } #header p { font-size: 12px; } #header p a { text-decoration: none; } #header p a:hover { border-width: 1px; }
4. 函数 & 运算
运算提供了加,减,乘,除操作,我们可以做属性值和颜色值得运算,这样就可以实现属性值之间的复杂关系。如下代码:
// 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代码如下:
/* 生成的 CSS */ #header { color: #333; border-left: 1px; border-right: 2px; } #footer { color: #114411; border-color: #7d2717; }
等等操作,我这边不一一列举。
注意: 1. 客户端这样引用less.js文件来解析style.less成真正的样式,在真正的项目中尽量不要这样使用,因为less.js压缩后的代码也有100KB,对于性能方面有一定的影响,且通过测试IE6-IE9并不支持。如果要使用less的话,我们建议最好使用node.js或其他第三方工具进行预编译。接下来我们会谈谈如何用nodejs来进行编译less文件。
2.在做demo时候,我们要预览效果要使用本地服务器环境下预览效果,不能直接在本地打开页面,否则这样会报错!如下:
2.服务器端使用nodeJS来对Less文件进行编译。
原理:进入项目中使用nodeJS对比如index.less 编译成index.css样式文件,我们在页面上直接引用index.css即可,其他的比如上面介绍客户端less.js都不需要。
步骤如下:
1. 确保本机已安装node及NPM(node包管理器),然后在终端命令下运行命令如下:
npm install less
如果你想下载最新文档版本的Less的话,可以尝试下面的操作:
npm install less@latest
演示如下:
2.假如项目中的目录如下:
其中index.less文件代码如下:
进入根目录中css文件下,使用如下命令:
lessc index.less > index.css (也可以把这句代码写到批处理bat里面,直接运行下即可)。
即可把index.less 编译成新的文件index.css,我们可以看看index.css文件代码如下:
我们现在再来看看根目录文件就多了一个index.css文件,如下:
其中test.bat是批处理文件 我们不管。
想更多的了解Less的话,可以看如下教程。
http://www.bootcss.com/p/lesscss/
在chrome浏览器下如何调式?
Less和sass一样,调试需要开启编译(koala)时输出调试信息和浏览器调试功能,两者缺一不可。
Less在chrome下如何设置,和sass一样的。
koala开启
koala是一个前端预处理器语言图形编译工具,支持Less、Sass、Compass、CoffeeScript,帮助web开发者更高效地使用它们进行开发。跨平台运行,完美兼容windows、linux、mac。 需要选下载安装,下载网址如下:
详情了解网址:http://koala-app.com/index-zh.html
开启浏览器调试
谷歌浏览器调试
F12打开调试面板,点击调试面板右上角的齿轮图标打开设置,在general
选项中勾选Enable CSS source map
和 Auto-reload generated CSS
。
f12
打开调试面板,就可以看到原先右边的css文件变成了我们现在的less文件.如下图
点击less文件,会跳到source
里面的less源文件,现在可以在里面进行修改,修改完成后可以右键选择save
或save as
命令,然后替换我们本地的less源文件,刷新chrome就可以看到变化(注意,解析样式需要一定时间)。以后只要ctrl+s
保存修改就可以在浏览器中看到修改效果了。
注意事项:切记项目文件名不能叫less文件夹,否则的话 编译不会生成map文件,也就是说无法定位到单独的less文件了。如下:
Sass
1. 定义:
Sass也是一种css预处理语言,语法也和Less类似,所以也不多说。
2. 配置教程(如何使用)。
Sass安装:
因为Sass依赖于ruby环境,所以装sass之前要先安装ruby,先到官网下载个ruby,地址:http://rubyinstaller.org/downloads 我下载的是Ruby 2.0.0-p481 (x64)
Ruby安装:
在安装的时候,请勾选Add Ruby executables to your PATH这个选项,添加环境变量,不然以后使用编译软件的时候会提示找不到ruby环境。如下:
Sass安装:
安装完ruby后,在开始菜单中,找到刚才我们安装的ruby,打开Start Command Prompt with Ruby。如下:
然后直接在命令行中输入如下命令:
gem install sass
最近因为墙的比较厉害,如果你没有安装成功,那么请参考下面的淘宝的RubyGems镜像安装sass,如果成功则忽略。
淘宝的RubyGems镜像安装sass安装方法:
由于国内网络原因(你懂的),导致 rubygems.org 存放在 Amazon S3 上面的资源文件间歇性连接失败。这时候我们可以通过gem sources
命令来配置源,先移除默认的https://rubygems.org
源,
然后添加淘宝的源https://ruby.taobao.org/
,然后查看下当前使用的源是哪个,如果是淘宝的,则表示可以输入sass安装命令gem install sass
了。
出现如下信息,表示安装成功了!
下面我们可以查看下Sass版本的命令如下:
你也可以运行帮助命令行来查看你需要的命令
Sass基本语法介绍:
1. 文件后缀名
sass有两种后缀名文件:一种后缀名为sass,不使用大括号和分号;另一种就是我们这里使用的scss文件,这种和我们平时写的css文件格式差不多,使用大括号和分号。而本教程中所说的所有sass文件都指后缀名为scss的文件。在此也建议使用后缀名为scss的文件,以避免sass后缀名的严格格式要求报错。如下图:
2. 变量
sass的变量必须是$开头,后面紧跟变量名,而变量值和变量名之间就需要使用冒号(:)分隔开(就像CSS属性设置一样),如果值后面加上!default则表示默认值。
普通变量
定义之后可以在全局范围内使用。如下图所示:
3. 嵌套
sass可以进行选择器的嵌套,表示层级关系。
如下图所示:
会被编译成如下样式:
4.导入
sass的导入(@import
)规则和CSS的有所不同,编译时会将@import
的scss文件合并进来只生成一个CSS文件。但是如果你在sass文件中导入css文件如@import 'reset.css'
,那效果跟普通CSS导入样式文件一样,导入的css文件不会合并到编译后的文件中,而是以@import
方式存在。
所有的sass导入文件都可以忽略后缀名.scss
。一般来说基础的文件命名方法以_开头,如_mixin.scss
。这种文件在导入的时候可以不写下划线,可写成@import "mixin"
。
如下图演示,其中
reset.css
是要被导入的文件。
Reset.css
生成后的
css
文件如下:
5.mixin
sass中使用@mixin
声明混合,可以传递参数,参数名以$符号开始,多个参数以逗号分开,也可以给参数设置默认值。声明的@mixin
通过@include
来调用。
如下:
生成后文件
6. 扩展/继承
sass中,选择器继承可以让选择器继承另一个选择器的所有样式,并联合声明。使用选择器的继承,要使用关键词@extend
,后面紧跟需要继承的选择器。
7.运算
sass具有运算的特性,可以对数值型的Value(如:数字、颜色、变量等)进行加减乘除四则运算。请注意运算符前后请留一个空格,不然会出错。
如下:
等等语法,这里列出一些简单的语法,如果想需要更多的学习Sass的话,可以请看Sass教程。地址: http://www.w3cplus.com/sassguide/
Sass如何编译
1. 单文件转换命令。
sass sass.scss sass.css
比如我项目结构如下:
我们先来看看a.scss文件
body {
background: #eee;
}
Reset.css 文件css如下:
div {color:red;}
sass.scss 文件代码如下:
@import "reset.css";
@import "a";
p{color:red;}
我运行test.bat处理命令如下:sass sass.scss sass.css
即可生成sass.css新文件,如下:
其中sass.css文件代码如下:
@import url(reset.css);
body {
background: #eee;
}
p {
color: red;
}
2. 对整个目录进行编译成css文件。
1. 首先需要安装rb-fsevent (更多学习https://github.com/thibaudgg/rb-fsevent/ )安装命令如下:
如上 说明已经安装完成。
接着我对上面sass项目下的sass文件进行编译成css文件,比如对上面Sass项目中的css文件夹下面的所有sass文件转换成css文件,如下图所示:
上面的意思是:对sass项目下的css文件所有的Sass文件 编译成css文件。最后编译如下目录结构,如下图:
更多的编译介绍 请看下面网址:
http://www.w3cplus.com/sassguide/compile.html
Sass调式
sass调试需要开启编译(koala)时输出调试信息和浏览器调试功能,两者缺一不可。
开启编译调试信息
目前sass的调试分为两种,一种为开启debug-info
,一种为开启sourcemap
(这个将成为主流)。
如开启的是debug-info
,则解析的css文件中会有以@media -sass-debug-info
开头的代码,如没有则表明没有开启。
如开启的是sourcemap
,则在解析的css文件同目录下生成一个.css.map
的后缀名文件。
命令行开启
两个的命令分别为--debug-info
,--sourcemap
,开启如下:
和
koala开启
koala是一个前端预处理器语言图形编译工具,支持Less、Sass、Compass、CoffeeScript,帮助web开发者更高效地使用它们进行开发。跨平台运行,完美兼容windows、linux、mac。 需要选下载安装,下载网址如下:
详情了解网址:http://koala-app.com/index-zh.html
如下图:点击相应的文件,然后就会出现右边的编译选项,即可选择是否开启source map
,debug info
开启浏览器调试
谷歌浏览器调试
F12打开调试面板,点击调试面板右上角的齿轮图标打开设置,在general
选项中勾选Enable CSS source map
和 Auto-reload generated CSS
。
开启--sourcemap
编译,f12
打开调试面板,就可以看到原先右边的css文件变成了我们现在的scss文件.
点击scss文件,会跳到source
里面的scss源文件,现在可以在里面进行修改,修改完成后可以右键选择save
或save as
命令,然后替换我们本地的scss源文件,刷新chrome就可以看到变化(注意,解析样式需要一定时间)。以后只要ctrl+s
保存修改就可以在浏览器中看到修改效果了。
Stylus
1.定义:
Stylus也是一门css预处理语言,可以创建健壮的,动态的,富有表现力的css. 默认使用 .styl 的作为文件扩展名,支持多样性的CSS语法。
2.配置教程(如何使用)。
Stylus也是基于nodejs的,如果没有安装nodejs,请先安装nodejs,可以到这个网址里面下载(http://nodejs.org/#download ),安装完后node自带了NPM(node包管理器)。
然后,在终端命令下安装stylus包,如下代码:npm install stylus
如上,说明已经安装成功了!
Stylus基本语法介绍:
一: 变量
我们可以指定表达式为变量,然后在我们的样式中贯穿使用:我们这样如下写:
第一种写法: font-size = 14px body font font-size Arial, sans-seri 编译成为如下这样: body { font: 14px Arial, sans-serif; } 第二种写法: 变量可以组成一个表达式列表 如下 font-size = 14px font = font-size "Lucida Grande", Arial body font font sans-serif 编译成为如下这样: body { font: 14px "Lucida Grande", Arial sans-serif; } 标示符(变量名,函数等),也可能包括$字符,如下: $font-size = 14px body { font: $font-size sans-serif; }
二:mixin(混入)
例如,下面有定义的border-radius(n)
方法,其却作为一个mixin(如,作为状态调用,而非表达式)调用。
当border-radius()
选择器中调用时候,属性会被扩展并复制在选择器中。
border-radius(n) -webkit-border-radius n -moz-border-radius n border-radius n form input[type=button] border-radius(5px) 会编译成如下代码: form input[type=button] { -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; } 使用混合书写,你可以完全忽略括号。 border-radius(n) -webkit-border-radius n -moz-border-radius n border-radius n form input[type=button] border-radius 5px 也可以编译成上面的一样。 还可以这样写: /*声明一个Mixin叫作“error”*/ error(borderWidth=2px){ border:borderWidth solid #f00; color: #f00; } /*调用error Mixins*/ .generic-error { error();/*直接调用error mixins*/ } .login-error { error(5px);/*调用error mixins,并将参数$borderWidth的值重定义为5px*/ } 会编译成如下代码: /*声明一个Mixin叫作“error”*/ .generic-error { border: 2px solid #f00; color: #f00; /*直接调用error mixins*/ } .login-error { border: 5px solid #f00; color: #f00; /*调用error mixins,并将参数$borderWidth的值重定义为5px*/ }
三:嵌套
CSS预处理器语言中的嵌套指的是在一个选择器中嵌套另一个选择器来实现继承,从而减少代码量,并且增加了代码的可读性。比如说,我们在CSS中多个元素有一个相同的父元素,那么写样式会变得很乏味,我们需要一遍一遍的在每个元素前写这个父元素,除非给特定的元素添加类名“class”或者ID。
如下代码:
section { margin:10px; nav { height:25px; a { color:#0982c1; &:hover { text-decoration:underline; } } } } 会编译成如下代码: section { margin: 10px; } section nav { height: 25px; } section nav a { color: #0982c1; } section nav a:hover { text-decoration: underline; }
4. 继承
Stylus的继承是把一个选择器的所有样式继承到另个选择器上。在继承另个选择器的样式时需要使用“@extend”开始,后面紧跟被继承的选择器:
如下代码:
.block { margin: 10px 5px; padding: 2px; } p { @extend .block;/*继承.block选择器下所有样式*/ border: 1px solid #eee; } ul,ol { @extend .block; /*继承.block选择器下所有样式*/ color: #333; text-transform: uppercase; } 他们会编译成如下代码: .block, p, ul, ol { margin: 10px 5px; padding: 2px; } p { /*继承.block选择器下所有样式*/ border: 1px solid #eee; } ul, ol { /*继承.block选择器下所有样式*/ color: #333; text-transform: uppercase; }
5. 方法(function)
Stylus强大之处就在于其内置的语言函数定义。其定义与混入(mixins)一致;却可以返回值。
返回值
很简单的例子,两数值相加的方法.
add(a, b) a + b body padding add(10px, 5) 会编译成如下代码: body { padding: 15px; } 变量函数 我们可以把函数当作变量传递到新的函数中。例如,invoke()接受函数作为参数,因此,我们可以传递add() 如下代码: invoke(a, b, fn) fn(a, b) add(a, b) a + b body padding invoke(5px, 10, add) 会编译成如下代码: body { padding: 15px; } 参数: arguments是所有函数体都有的局部变量,包含传递的所有参数。 比如如下代码 sum() n = 0 for num in arguments n = n + num body padding sum(1px,2,3,4,5,6) 会编译成如下代码: body { padding: 21px; }
6. 导入(important)
在CSS中,并不喜欢用@import来导入样式,因为这样的做法会增加http的请求。但是在CSS预处理器中的导入(@import)规则和CSS的有所不同,它只是在语义上导入不同的文件,但最终结果是生成一个CSS文件。如果你是通赤“@import ‘file.css’”导入“file.css”样式文件,那效果跟普通CSS导入样式文件一样。注意:导入文件中定义了变量、混合等信息也将会被引入到主样式文件中,因此需要避免他们的相互冲突。
Sass Less及Stylus对于导入都是一样的,这里就不列举列子哦,具体的可以看Sass或者Less了。
对于Stylus还有更多高级语法:如果想要继续了解更多的话,可以看如下文章:
中文版的张鑫旭翻译的 http://www.zhangxinxu.com/jq/stylus/functions.php
英文原版的 http://learnboost.github.io/stylus/
对于styl文件如何编译?
比如项目目录结构如下:
编译文件有如下几种方式:
1. 如果我们想编译单个文件,比如下编译css2下的test.styl的话,我们可以做如下操作,首先进入项目中css2文件夹里面,然后输入如下语句:stylus <test.styl> test.css
Ok后在目录下会生成一个test.css文件了 如下
其中test.styl 代码如下:
font-size = 14px
body font font-size Arial, sans-seri
编译成如下代码:
body { font: 14px Arial, sans-seri;}
2. 如果我们想一起编译2个文件或者多个文件要如何编译呢?
我们可以这样编译:stylus test.styl test2.styl …
3. 我们也可以对一整个文件夹进行编译。比如文件夹为css2,我想对css2下的所有styl文件进行编译:如下代码:
stylus css2
4. 如果编译完成后,我们需要对css压缩的话,我们可以执行如下代码:
stylus --compress <test.styl> test.css
就可以对test.css压缩了。
Less Sass Stylus三者比较
一:变量
Less 的变量名使用 @ 符号开始:如下代码:
@mainColor: #0982c1; @siteWidth: 1024px; @borderStyle: dotted; body { color: @mainColor; border: 1px @borderStyle @mainColor; max-width: @siteWidth; }
Sass 的变量必须是 $ 开始,然后变量名和值使用冒号隔开,跟 CSS 的属性一致:$mainColor: #0982c1;
$siteWidth: 1024px; $borderStyle: dotted; body { color: $mainColor; border: 1px $borderStyle $mainColor; max-width: $siteWidth; }
Stylus 对变量名没有任何限定,你可以是 $ 开始,也可以是任意的字符,而且与变量值之间可以用冒号、空格隔开,需要注意的是 Stylus (0.22.4) 将会编译 @ 开始的变量,但其对应的值并不会赋予该变量,换句话说,在 Stylus 的变量名不要用 @ 开头。如下代码:
mainColor = #0982c1
siteWidth = 1024px
$borderStyle = dotted
Body
color mainColor
border 1px $borderStyle mainColor
max-width siteWidth
上面的三种不同的 CSS 预处理器的写法,最终都将产生相同的结果:
body { color: #0982c1; border: 1px dotted #0982c1; max-width: 1024px; }
二:嵌套
如果我们需要在CSS中相同的 parent 引用多个元素,这将是非常乏味的,你需要一遍又一遍地写 parent。Less Sass Stylus三者一样的语法。例如:
section { margin: 10px; nav { height: 25px; a { color: #0982C1; &:hover { text-decoration: underline; } } } }
最终都生成css代码如下:
section { margin: 10px; } section nav { height: 25px; } section nav a { color: #0982C1; } section nav a:hover { text-decoration: underline; }
三:Mixins(混入)
Less CSS 的混入语法:
.error(@borderWidth: 2px) { border: @borderWidth solid #F00; color: #F00; } .generic-error { padding: 20px; margin: 4px; .error(); } .login-error { left: 12px; position: absolute; top: 20px; .error(5px); }
Sass 的混入语法:
@mixin error($borderWidth: 2px) { border: $borderWidth solid #F00; color: #F00; } .generic-error { padding: 20px; margin: 4px; @ include error(); } .login-error { left: 12px; position: absolute; top: 20px; @ include error(5px); }
Stylus 的混入语法:
error(borderWidth= 2px) { border: borderWidth solid #F00; color: #F00; } .generic-error { padding: 20px; margin: 4px; error(); } .login-error { left: 12px; position: absolute; top: 20px; error(5px); }
最终它们都将编译成如下的 CSS 样式:
.generic-error { padding: 20px; margin: 4px; border: 2px solid #f00; color: #f00; } .login-error { left: 12px; position: absolute; top: 20px; border: 5px solid #f00; color: #f00; }
四:继承
当我们需要为多个元素定义相同样式的时候,我们可以考虑使用继承的做法。例如我们经常需要:
在 Sass 和 Stylus 我们可以这样写:
.block { margin: 10px 5px; padding: 2px; } p { @extend .block; border: 1px solid #EEE; } ul, ol { @extend .block; color: #333; text-transform: uppercase; }
最终编译成如下代码:
.block, p, ul, ol { margin: 10px 5px; padding: 2px; } p { border: 1px solid #EEE; } ul, ol { color: #333; text-transform: uppercase; }
在这方面 Less 表现的稍微弱一些,更像是混入写法:
.block { margin: 10px 5px; padding: 2px; } p { .block; border: 1px solid #EEE; } ul, ol { .block; color: #333; text-transform: uppercase; }
最终被编译成如下代码:
.block { margin: 10px 5px; padding: 2px; } p { margin: 10px 5px; padding: 2px; border: 1px solid #EEE; } ul, ol { margin: 10px 5px; padding: 2px; color: #333; text-transform: uppercase; }
五:导入
很多 CSS 开发者对导入的做法都不太感冒,因为它需要多次的 HTTP 请求。但是在 CSS 预处理器中的导入操作则不同,它只是在语义上包含了不同的文件,但最终结果是一个单一的 CSS 文件,如果你是通过 @ import "file.css"; 导入 CSS 文件,那效果跟普通的 CSS 导入一样。注意:导入文件中定义的混入、变量等信息也将会被引入到主样式文件中,因此需要避免它们互相冲突。LESS Sass及Stylus都一样,如下目录代码
其中test.styl代码如下:
font-size = 14px
body
font font-size Arial, sans-seri
main.styl代码如下:
@import "index.css";
@import "test.styl";
p {
background: #0982C1;
}
Index.css代码如下:
p {
color #3333;
}
编译运行 stylus <main.styl> main.css 最终生成代码如下:
@import "index.css";
body {
font: 14px Arial, sans-seri;
}
p {
background: #0982c1;
}
六:运算符:(三者一样)
你可以直接在 CSS 预处理器中进行样式的计算,例如:
body {
margin: (14px/2);
top: 50px + 100px;
right: 100px - 50px;
left: 10 * 10;
}
最终编译代码如下:
body {
margin: 7px;
top: 150px;
right: 50px;
left: 100;
}
以上是基本的语法比较,一些函数一般情况下css用不到,所以没有列出来。
如果大家对stylus感兴趣的话,希望大家研究下stylus哦!关键是如何使用chrome或者firefox如何更方便的调式,和上面的Less或者Sass一样的方便调式,我们大家都知道 stylus比less sass语法更方便,使用起来更好,但是目前我没有看到Stylus的调式没有Less,sass方便,因此想问问大家有没有使用过Stylus开发项目?那么如果用过如何更方便的调式代码?希望大家有研究过希望能分享下?谢谢了!