使用wxss为响应式开发带来的一些模式和思维上的改变

使用wxss为响应式开发带来的一些模式和思维上的改变。
WXSS(WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式。

WXSS 用来决定 WXML 的组件应该怎么显示。

为了适应广大的前端开发者,我们的 WXSS 具有 CSS 大部分特性。 同时为了更适合开发微信小程序,我们对 CSS 进行了扩充以及修改。

与 CSS 相比我们扩展的特性有:
rem的重定义

前端工程师对rem非常熟悉,rem是以html元素的font-size为基准的尺寸计量单位。rem方便了开发者对响应式UI的尺寸进行统筹管理。

wxss中的rem与css中的rem的含义完全不同,下面是微信官方文档中对rem的定义:

    rem(root em): 规定屏幕宽度为20rem;1rem = (750/20)rpx

其中的750这个数值是wxss将设备屏幕的宽统一定义为750rpx,对此,下文会讲解。 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML Strict//EN">
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
<html lang="zh-cn">

<head>
    <style>
		
.cnblogs-markdown .hljs,blockquote,html{background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}#mainContent,.cnblogs-markdown .hljs,blockquote,html{background-image:none;background-repeat:repeat;background-position-x:0;background-position-y:0}pre{margin-top:0;margin-bottom:0;white-space:pre-wrap;word-wrap:break-word}blockquote{margin-top:10px;margin-bottom:10px;background-color:transparent;border-color:#efefef;border-width:2px;border-style:solid}#cnblogs_post_body{margin-bottom:20px}#cnblogs_post_body ul{padding-left:0;margin-left:30px}#cnblogs_post_body ol{padding-left:40px}#cnblogs_post_body ol li{list-style-type:decimal}#cnblogs_post_body ul li{list-style-type:disc}#cnblogs_post_body p{text-indent:0;margin:10px auto}#cnblogs_post_body h3{line-height:1.5;font-size:16px;font-weight:700;margin:10px 0}.cnblogs-markdown .hljs,.cnblogs-markdown code{font-family:"Courier New",sans-serif!important;font-size:12px!important}.cnblogs-markdown .hljs{color:#000;display:block;overflow-x:auto;background-color:#fff}.hljs-built_in,.hljs-keyword,.hljs-name,.hljs-selector-tag,.hljs-tag{color:#00f}.hljs-addition,.hljs-attribute,.hljs-literal,.hljs-section,.hljs-string,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type{color:#a31515}.hljs-attr{color:red}.cnblogs-markdown code{line-height:1.8;vertical-align:middle;display:inline-block;background-color:#f5f5f5!important;padding:0 5px!important;margin:1px 5px;border-color:#ccc!important;border-width:1px!important;border-style:solid!important;border-radius:3px!important}.cnblogs-markdown pre code{height:auto;line-height:normal;vertical-align:auto;display:block;margin:auto}.cnblogs-markdown .hljs{line-height:1.5!important;padding:5px!important}.cnblogs-markdown pre{margin-top:10px;margin-bottom:10px}body{background-image:url(images/bg.gif);background-repeat:repeat;background-color:#fffdfa}html{color:#000;overflow-y:scroll;background-color:#fff}blockquote,body,button,dd,dl,dt,fieldset,form,h1,h2,h3,h4,h5,h6,hr,input,lengend,li,ol,p,pre,td,textarea,th,ul{list-style-type:none;list-style-image:none;padding:0;margin:0}body,button,input,select,textarea{line-height:1.5;font-family:Tahoma,Arial,Helvetica,sans-serif;font-size:12px;font-style:normal;font-variant:normal;font-weight:400;font-size-adjust:none;font-stretch:normal}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:400}address,cite,dfn,em,var{font-style:normal}code,kbd,pre,samp,tt{font-family:"Courier New",Courier,monospace}ol,ul{list-style:none}a:link,a:visited{color:#39f;text-decoration:none}:focus{outline:0}fieldset,img{border-color:currentColor;border-width:medium;border-style:none}img{-ms-interpolation-mode:bicubic}#blogTitle,#footer,#main,#navigator{width:1000px;position:relative;margin:0 auto}#main{margin-top:6px;margin-bottom:0;background-color:#f5f5f5}#mainContent,.postBody blockquote,.postCon blockquote{background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box;background-color:#fff}#mainContent{width:765px;float:left;display:inline-block;box-shadow:0 0 8px #999;border-radius:6px}.entrylistPostSummary,.postBody,.postCon{clear:both;margin-top:26px;color:#444;line-height:1.8;font-size:14px}.postBody h3,.postCon h3{font-size:16px}.postBody ul,.postCon ul{margin-left:20px;list-style:none}.postBody ul li,.postCon ul li{list-style:disc inside}.postBody ol,.postCon ol{margin-left:20px;list-style:none}.postBody blockquote,.postCon blockquote{width:90%;color:#666;background-image:url(/images/blockquote.gif);background-repeat:no-repeat;background-position-x:left;background-position-y:top;padding:6px 0 6px 45px;margin:0 auto}.post{padding:32px}.forFlow p{margin-bottom:18px}.forFlow img{margin-top:20px;margin-bottom:20px}#cnblogs_post_body{font-size:14px}#cnblogs_post_body img{max-width:650px}

</style></head><body> <div id="home"> <div id="main"> <div id="mainContent"> <div class="forFlow"> <div id="post_detail"> <div id="topics"> <div class="post"> <div class="postBody"> <div class="cnblogs-markdown" id="cnblogs_post_body"> <p> 使用wxss为响应式开发带来的一些模式和思维上的改变。 </p> <h3 id="rem的重定义"> rem的重定义 </h3> <p> 前端工程师对<code>rem</code>非常熟悉,rem是以html元素的<code>font-size</code>为基准的尺寸计量单位。rem方便了开发者对响应式UI的尺寸进行统筹管理。 </p> <p> wxss中的<code>rem</code>与css中的<code>rem</code>的含义完全不同,下面是微信官方文档中对rem的定义: </p> <blockquote> <p> rem(root em): 规定屏幕宽度为20rem;1rem = (750/20)rpx </p> </blockquote> <p> 其中的750这个数值是<strong>wxss将设备屏幕的宽统一定义为750rpx</strong>,对此,下文会讲解。 </p> <p> 各位读到这里是否脑海里浮现了一个想法:<strong>wxss的rem怎么听起来有点像bootstrap的<a href="http://v3.bootcss.com/css/#grid">栅格系统</a>呢?</strong> </p> <p> wxss将屏幕宽分为20rem,bootstrap将设备屏幕宽度分为12列。初看起来确实有点类似。但其实wxss的rem和bootstrap的栅格系统并不相同。虽然wxss和bootstrap都是讲屏幕尺寸分割为单元格,但rem和栅格的定位不同。 </p> <p> bootstrap的开发者使用指定的classname进行元素间的比例分配,这其实接近为css3中的flexbox;而wxss的rem是一个<em>尺寸单位</em>,你可以在<strong>合理的场景</strong>下将任何以<code>px</code>为单位的属性值替换为<code>rem</code>。 </p> <p> 所以,开发小程序UI时,需要抛弃思维中对rem的常规认知。截止目前,笔者还未遇到必须使用小程序rem的需求,希望大家踊跃探讨。 </p> <h3 id="rpx的奇妙之处"> rpx的奇妙之处 </h3> <p> 上文提到wxss将设备屏幕的宽统一定义为750rpx,其中的rpx是wxss带来的新的尺寸单位。rpx的定义如下: </p> <blockquote> <p> rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。 </p> </blockquote> <p> css中的px与设备的物理像素并非绝对的一比一关系。尤其是在移动设备上,px与物理像素的比例与设备的dpr(devicePixelRadio)有关,详细的对应关系各位可自行查阅。 </p> <p> rpx称为相对像素值,rpx与物理像素也并非绝对的一比一关系。wxss将设备宽定义为750rpx,是以iPhone6的分辨率(750x1334)为基准划分的。也就是说,在iPhone6上,1rpx=1物理像素=0.5px。官方文档列出了几种屏幕的rpx对应关系如下: <br /> <img src="https://i-blog.csdnimg.cn/blog_migrate/a6396b489cfdc3d3e4809d738a9f9651.png" /> </p> <p> 大家可以从中得到rpx和px的换算公式: </p> <blockquote> <p> 1rpx = 1px/dpr </p> </blockquote> <p> 其中iPhone6的dpr=2。 </p> <p> 那么rpx带给响应式UI什么改变呢? </p> <p> 目前大部分UI工程师在制作UI稿的时候是按照iPhone6的尺寸设计,然后前端工程师按照UI稿尺寸的一半进行UI的还原开发。这样在iPhone6以及接近iPhone6尺寸的设备上是没有任何问题的。但是移动设备的尺寸多种多样,我们的产品不可能只应对iPhone6(况且iPhone7已经来了哈哈...),所以通常的做法是使用css的媒体查询根据设备的尺寸再进行适配微调。 </p> <p> 如果使用rpx是不是就可以解决这个问题呢?笔者在开发过程中尝试使用rpx代替px,使用UI稿的原始尺寸还原UI,截止到目前体验非常好。rpx本身代表的是相对像素,所以不论多大尺寸的屏幕,<strong>rpx的UI占据的屏幕比例是绝对固定的</strong>,是等比缩放的。 </p> <p> 但是rpx并非万能的,比如使用css sprites的图标。请看下文。 </p> <h3 id="sprites图标的响应式处理"> sprites图标的响应式处理 </h3> <p> 使用css sprites作为图标背景时,每个图标的尺寸是以px为单位固定的,比如: </p> <div class="sourceCode"> <pre class="sourceCode css"> <code class="sourceCode css hljs"><span class="fl"><span class="hljs-selector-class">.icon</span></span><span class="kw">{</span> <span class="kw"><span class="hljs-attribute">background-image</span>:</span> <span class="dt"><span class="hljs-built_in">url</span>(</span><span class="st"><span class="hljs-string">'//image.daojia.com/icon.png'</span></span><span class="dt">)</span><span class="kw">;</span> <span class="kw"><span class="hljs-attribute">display</span>:</span> <span class="dt">inline-block</span><span class="kw">;</span> <span class="kw"><span class="hljs-attribute">vertical-align</span>:</span> <span class="dt">middle</span><span class="kw">;</span> <span class="kw">}</span> <span class="fl"><span class="hljs-selector-class">.icon__circle</span></span><span class="kw">{</span> <span class="kw"><span class="hljs-attribute">background-position</span>:</span> <span class="dt"><span class="hljs-number">0</span></span> <span class="dt"><span class="hljs-number">0</span></span><span class="kw">;</span> <span class="kw"><span class="hljs-attribute">width</span>:</span> <span class="dt"><span class="hljs-number">40px</span></span><span class="kw">;</span> <span class="kw"><span class="hljs-attribute">height</span>:</span> <span class="dt"><span class="hljs-number">40px</span></span><span class="kw">;</span> <span class="kw">}</span></code> </pre> </div> <p> 如果图标的尺寸不符合UI设计,则进行一定比例的缩放: </p> <div class="sourceCode"> <pre class="sourceCode css"> <code class="sourceCode css hljs"><span class="fl"><span class="hljs-selector-class">.icon__circle</span></span><span class="kw">{</span> <span class="kw"><span class="hljs-attribute">transform</span>:</span> <span class="hljs-built_in">scale</span>(<span class="dt"><span class="hljs-number">0.5</span></span>)<span class="kw">;</span> <span class="kw">}</span></code> </pre> </div> <p> 也就是说,使用sprites图标不可避免地会用到px,如果与rpx结合使用,是不能保证同rpx一样等比缩放效果的。那么怎么去解决这个问题呢? </p> <p> 根据上文总结出的rpx与px的换算公式,如果想要将以px规定的UI达到同rpx一样的响应式缩放效果,必须将px与设备的dpr进行计算。但是css作为一种标记语言,并不具备动态特性,无法动态地获取设备dpr并计算。所以,单纯使用wxss并不能解决上文提到的问题。 </p> <p> 好消息是小程序提供了获取设备信息的API,并且支持CommonJS模块化方案。有了这些功能,我们可以在封装组件时加入动态的逻辑配置。 </p> <p> 还是以上文的代码为例,sprites图的<code>icon__circle</code>尺寸为40px*40px,我们的目标是将其适配为20rpx,以下是笔者的开发方案。 </p> <p> 比如项目中有一个user组件,包含了一些sprites图标节点。user组件的文件目录如下: </p> <ul> <li> <code>user.wxml</code> - 组件模板; </li> <li> <code>user.wxss</code> - 组件样式; </li> <li> <code>user.js</code> - 组件逻辑。 </li> </ul> <p> 首先给<code>user.wxml</code>中icon对应的element设置动态的<code>transform</code>: </p> <div class="sourceCode"> <pre class="sourceCode xml"> <code class="sourceCode xml hljs"><span class="kw"><span class="hljs-tag"><<span class="hljs-name">view</span></span></span><span class="ot"><span class="hljs-tag"> <span class="hljs-attr">class</span>=</span></span><span class="st"><span class="hljs-tag"><span class="hljs-string">'icon icon__circle'</span></span></span><span class="ot"><span class="hljs-tag"> <span class="hljs-attr">style</span>=</span></span><span class="st"><span class="hljs-tag"><span class="hljs-string">"transform: scale({{iconScale}})"</span></span></span><span class="kw"><span class="hljs-tag">></span><span class="hljs-tag"></<span class="hljs-name">view</span>></span></span></code> </pre> </div> <p> 其中<code>iconScale</code>是引用user的外部组件index传递给user组件的: </p> <div class="sourceCode"> <pre class="sourceCode xml"> <code class="sourceCode xml hljs"><span class="kw"><span class="hljs-tag"><<span class="hljs-name">import</span></span></span><span class="ot"><span class="hljs-tag"> <span class="hljs-attr">src</span>=</span></span><span class="st"><span class="hljs-tag"><span class="hljs-string">'user.wxml'</span></span></span><span class="kw"><span class="hljs-tag">/></span></span> <span class="kw"><span class="hljs-tag"><<span class="hljs-name">template</span></span></span><span class="ot"><span class="hljs-tag"> <span class="hljs-attr">is</span>=</span></span><span class="st"><span class="hljs-tag"><span class="hljs-string">'product-user'</span></span></span><span class="ot"><span class="hljs-tag"> <span class="hljs-attr">data</span>=</span></span><span class="st"><span class="hljs-tag"><span class="hljs-string">"{{iconScale: userIconScale}}"</span></span></span><span class="kw"><span class="hljs-tag">/></span></span></code> </pre> </div> <p> userIconScale是index组件的一个data,userIconScale的值并非index组件规定的,而是由index组件的js调用<code>user.js</code>动态获取的。以下代码是<code>user.js</code>暴露的API: </p> <div class="sourceCode"> <pre class="sourceCode javascript"> <code class="sourceCode javascript hljs"><span class="kw"><span class="hljs-keyword">const</span></span> ORIGIN_ICON_PX <span class="op">=</span> <span class="dv"><span class="hljs-number">40</span></span><span class="op">;</span> <span class="kw"><span class="hljs-keyword">const</span></span> TARGET_ICON_RPX <span class="op">=</span> <span class="dv"><span class="hljs-number">20</span></span><span class="op">;</span> <span class="va"><span class="hljs-built_in">module</span></span>.<span class="at">exports</span> <span class="op">=</span> <span class="op">{</span> <span class="at">getIconScale</span>() <span class="op">{</span> <span class="kw"><span class="hljs-keyword">let</span></span> result <span class="op">=</span> <span class="dv"><span class="hljs-number">1</span></span><span class="op">;</span> <span class="va">wx</span>.<span class="at">getSystemInfo</span>(<span class="op">{</span> <span class="dt">success</span><span class="op">:</span> <span class="kw"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(<span class="hljs-params">res</span>) </span><span class="op">{</span> <span class="kw"><span class="hljs-keyword">let</span></span> _dpr <span class="op">=</span> <span class="va">res</span>.<span class="at">pixelRatio</span><span class="op">;</span> result <span class="op">=</span> TARGET_ICON_RPX/(ORIGIN_ICON_PX <span class="op">*</span> _dpr)<span class="op">;</span> <span class="op">}</span> <span class="op">}</span>)<span class="op">;</span> <span class="cf"><span class="hljs-keyword">return</span></span> result<span class="op">;</span> <span class="op">}</span> <span class="op">}</span></code> </pre> </div> <p> 然后在index组件的js中调用以上API: </p> <div class="sourceCode"> <pre class="sourceCode javascript"> <code class="sourceCode javascript hljs"><span class="kw"><span class="hljs-keyword">let</span></span> getIconScale <span class="op">=</span> <span class="at"><span class="hljs-built_in">require</span></span>(<span class="st"><span class="hljs-string">'user.js'</span></span>).<span class="at">getIconScale</span><span class="op">;</span> <span class="at">Page</span>(<span class="op">{</span> <span class="dt">data</span><span class="op">:</span> <span class="op">{</span> <span class="dt">userIconScale</span><span class="op">:</span> <span class="dv"><span class="hljs-number">1</span></span> <span class="op">},</span> <span class="at">onLoad</span>()<span class="op">{</span> <span class="kw"><span class="hljs-keyword">this</span></span>.<span class="at">setData</span>(<span class="op">{</span> <span class="dt">userIconScale</span><span class="op">:</span> <span class="at">getIconScale</span>() <span class="op">}</span>)<span class="op">;</span> <span class="op">}</span> <span class="op">}</span>)<span class="op">;</span></code> </pre> </div> <p> 以上只是初步的方案,很多地方需要再仔细琢磨。不过以上方案基本上具备了一个组件的逻辑封装,并且达到了我们对响应式的开发需求。 </p> </div> </div> </div> </div> </div> </div> </div> </div> </div></body></html>

使用wxss为响应式开发带来的一些模式和思维上的改变。

rem的重定义

前端工程师对rem非常熟悉,rem是以html元素的font-size为基准的尺寸计量单位。rem方便了开发者对响应式UI的尺寸进行统筹管理。

wxss中的rem与css中的rem的含义完全不同,下面是微信官方文档中对rem的定义:

rem(root em): 规定屏幕宽度为20rem;1rem = (750/20)rpx

其中的750这个数值是wxss将设备屏幕的宽统一定义为750rpx,对此,下文会讲解。

各位读到这里是否脑海里浮现了一个想法:wxss的rem怎么听起来有点像bootstrap的栅格系统呢?

wxss将屏幕宽分为20rem,bootstrap将设备屏幕宽度分为12列。初看起来确实有点类似。但其实wxss的rem和bootstrap的栅格系统并不相同。虽然wxss和bootstrap都是讲屏幕尺寸分割为单元格,但rem和栅格的定位不同。

bootstrap的开发者使用指定的classname进行元素间的比例分配,这其实接近为css3中的flexbox;而wxss的rem是一个尺寸单位,你可以在合理的场景下将任何以px为单位的属性值替换为rem

所以,开发小程序UI时,需要抛弃思维中对rem的常规认知。截止目前,笔者还未遇到必须使用小程序rem的需求,希望大家踊跃探讨。

rpx的奇妙之处

上文提到wxss将设备屏幕的宽统一定义为750rpx,其中的rpx是wxss带来的新的尺寸单位。rpx的定义如下:

rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。

css中的px与设备的物理像素并非绝对的一比一关系。尤其是在移动设备上,px与物理像素的比例与设备的dpr(devicePixelRadio)有关,详细的对应关系各位可自行查阅。

rpx称为相对像素值,rpx与物理像素也并非绝对的一比一关系。wxss将设备宽定义为750rpx,是以iPhone6的分辨率(750x1334)为基准划分的。也就是说,在iPhone6上,1rpx=1物理像素=0.5px。官方文档列出了几种屏幕的rpx对应关系如下: 

大家可以从中得到rpx和px的换算公式:

1rpx = 1px/dpr

其中iPhone6的dpr=2。

那么rpx带给响应式UI什么改变呢?

目前大部分UI工程师在制作UI稿的时候是按照iPhone6的尺寸设计,然后前端工程师按照UI稿尺寸的一半进行UI的还原开发。这样在iPhone6以及接近iPhone6尺寸的设备上是没有任何问题的。但是移动设备的尺寸多种多样,我们的产品不可能只应对iPhone6(况且iPhone7已经来了哈哈...),所以通常的做法是使用css的媒体查询根据设备的尺寸再进行适配微调。

如果使用rpx是不是就可以解决这个问题呢?笔者在开发过程中尝试使用rpx代替px,使用UI稿的原始尺寸还原UI,截止到目前体验非常好。rpx本身代表的是相对像素,所以不论多大尺寸的屏幕,rpx的UI占据的屏幕比例是绝对固定的,是等比缩放的。

但是rpx并非万能的,比如使用css sprites的图标。请看下文。

sprites图标的响应式处理

使用css sprites作为图标背景时,每个图标的尺寸是以px为单位固定的,比如:

   .icon{
     background-image: url('//image.daojia.com/icon.png');
     display: inline-block;
     vertical-align: middle;
   }
   .icon__circle{
     background-position: 0 0;
     width: 40px;
     height: 40px;
   }
  

如果图标的尺寸不符合UI设计,则进行一定比例的缩放:

   .icon__circle{
       transform: scale(0.5);
   }
  

也就是说,使用sprites图标不可避免地会用到px,如果与rpx结合使用,是不能保证同rpx一样等比缩放效果的。那么怎么去解决这个问题呢?

根据上文总结出的rpx与px的换算公式,如果想要将以px规定的UI达到同rpx一样的响应式缩放效果,必须将px与设备的dpr进行计算。但是css作为一种标记语言,并不具备动态特性,无法动态地获取设备dpr并计算。所以,单纯使用wxss并不能解决上文提到的问题。

好消息是小程序提供了获取设备信息的API,并且支持CommonJS模块化方案。有了这些功能,我们可以在封装组件时加入动态的逻辑配置。

还是以上文的代码为例,sprites图的icon__circle尺寸为40px*40px,我们的目标是将其适配为20rpx,以下是笔者的开发方案。

比如项目中有一个user组件,包含了一些sprites图标节点。user组件的文件目录如下:

  • user.wxml - 组件模板;
  • user.wxss - 组件样式;
  • user.js - 组件逻辑。

首先给user.wxml中icon对应的element设置动态的transform

   <view class='icon icon__circle' style="transform: scale({{iconScale}})"></view>
  

其中iconScale是引用user的外部组件index传递给user组件的:

   <import src='user.wxml'/>
   <template is='product-user' data="{{iconScale: userIconScale}}"/>
  

userIconScale是index组件的一个data,userIconScale的值并非index组件规定的,而是由index组件的js调用user.js动态获取的。以下代码是user.js暴露的API:

   const ORIGIN_ICON_PX = 40;
   const TARGET_ICON_RPX = 20;
   
   module.exports = {
     getIconScale() {
       let result = 1;
       wx.getSystemInfo({
         success: function(res) {
           let _dpr = res.pixelRatio;
           result = TARGET_ICON_RPX/(ORIGIN_ICON_PX * _dpr);
         }
       });
       return result;
     }
   }
  

然后在index组件的js中调用以上API:

   let getIconScale = require('user.js').getIconScale;
   Page({
       data: {
           userIconScale: 1
       },
       onLoad(){
           this.setData({
               userIconScale: getIconScale()
           });
       }
   });
  

以上只是初步的方案,很多地方需要再仔细琢磨。不过以上方案基本上具备了一个组件的逻辑封装,并且达到了我们对响应式的开发需求。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Monster0936

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值