如何从头开始构建WordPress主题:基础知识

In this tutorial, we’ll explore WordPress theme file structure in depth, and learn how to create a basic WordPress theme from scratch.

在本教程中,我们将深入探讨WordPress主题文件的结构,并学习如何从头开始创建基本的WordPress主题。

In the first part of this series, we introduced WordPress theming, and the fundamental terminology relating to WordPress theme development. We covered templates, partials, template hierarchy, WordPress post types, the style.css stylesheet, WordPress filter and action hooks, WordPress loop, conditional tags, and we briefly took a look at a typical simple WordPress theme file structure.

本系列第一部分中 ,我们介绍了WordPress主题,以及与WordPress主题开发有关的基本术语。 我们介绍了模板局部视图模板层次结构WordPress帖子类型style.css样式表,WordPress 过滤器操作钩子, WordPress循环条件标签 ,并简要介绍了一个典型的简单WordPress主题文件结构。

创建裸机最低主题 (Creating the Bare Minimum Theme)

The first thing we’ll do is install a plugin that will enable us to batch create WordPress posts and other content. This way, we’ll be able to quickly populate our development website without losing too much time. One plugin that serves this purpose is FakerPress by Gustavo Bordoni, available in the WordPress plugin repository.

我们要做的第一件事是安装一个插件,使我们能够批量创建WordPress帖子和其他内容。 这样,我们将能够快速填充我们的开发网站而不会浪费太多时间。 用于此目的的一个插件是Gustavo Bordoni的 FakerPress ,可在WordPress插件存储库中找到。

We quickly install and activate the plugin via WP-CLI.

我们通过WP-CLI快速安装并激活插件。

Now, when we log in to the admin dashboard, we’ll see that FakerPress is installed, and we can create all sorts of content in batch, including any custom post types we have.

现在,当我们登录到管理仪表盘时,我们将看到已安装FakerPress,并且可以批量创建各种内容,包括我们拥有的任何自定义帖子类型。

FakerPress is installed

Now, using this plugin, we’ll create some fake content. This is the result, using the default TwentySeventeen WordPress theme:

现在,使用此插件,我们将创建一些虚假内容。 这是使用默认的TwentySeventeen WordPress主题的结果:

The TwentySeventeen theme with placeholder content

Now, we quickly dive in and set up a bare minimum theme that consists of the catch-all index.php file, and style.css, which we need for the WordPress templating system to recognize the theme:

现在,我们快速进入并设置一个基本的最小主题,该主题由万能的index.php文件和style.css ,WordPress模板系统需要这些主题才能识别该主题:

/*
Theme Name: Botega Simple Theme
Theme URI: https://botega.co.uk
Author: Tonino Jankov
Author URI: https://botega.co.uk
Description: Basic WordPress theme for Sitepoint theme building tutorial
Text Domain: bsimple
Version: 1.0.0
License: GNU General Public License v2 or later
*/

This is the style.css, which consists only of meta CSS comments for now. These comments are required.

这是style.css ,目前仅包含meta CSS注释。 这些注释是必需的。

This is the index.php file. It will catch all the requests for now:

这是index.php文件。 它将立即捕获所有请求:

<?php
/**
 *
 * @package Botega_Scratch_Theme
 */
?>

<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
    <title><?php bloginfo('name'); ?></title>
    <link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>">
    <?php wp_head(); ?>
</head>
<body>

      <header>
         <h1><?php bloginfo('name'); ?></h1>
         <h3><?php bloginfo('description'); ?></h3>
      </header>

        <?php
        if ( have_posts() ) :
            /* Start the Loop */
            while ( have_posts() ) :
                the_post();
            endwhile;
        endif;
        ?>

</body>

We now upload and activate the minimal theme we have. I activate it using WP-CLI:

现在,我们上传并激活我们拥有的最小主题。 我使用WP-CLI激活它:

The theme is now visible to WordPress, and is active:

该主题现在对WordPress可见,并且处于活动状态:

The theme is now activated

We haven’t provided a screenshot, so the display in the backend is basic.

我们没有提供屏幕截图,因此后端的显示是基本的。

If we visit our website now in the browser, this is what we’ll see:

如果我们现在在浏览器中访问我们的网站,将会看到以下内容:

The current home page

Obviously, we have work to do.

显然,我们有工作要做。

If we view the source code of the home page, we’ll see that the wp_head() function has outputted a lot of default WordPress tags in the <head>, like CSS, JavaScript, link and meta tags.

如果查看主页的源代码,我们会看到wp_head()函数在<head>输出了许多默认的WordPress标签,例如CSS,JavaScript, linkmeta标签。

The bloginfo() function is used to output website information.

bloginfo()函数用于输出网站信息

Our home page is empty, because we aren’t outputting anything inside the Loop — a pattern that WordPress uses in all of its templates to output content.

我们的主页为空,因为我们没有在Loop内输出任何内容-WordPress在其所有模板中使用的一种模式来输出内容。

The Codex page about the Loop goes deep into details about it. A typical structure for the loop — which is based on PHP while control structure — looks like this:

有关循环的法典”页面将深入介绍其细节。 循环的典型结构-基于PHP 控制结构-如下所示:

<?php
if ( have_posts() ) {
    while ( have_posts() ) {
        the_post();
        //
        // Post Content here
        //
    } // end while
} // end if
?>

We need to fill that while loop with content — or with content-outputting WordPress tags.

我们需要用内容或输出内容的WordPress标签填充while循环。

If we change our loop, by adding the_title(), the_excerpt(), and we add HTML markup and the_ID(), to look like this:

如果更改循环,则添加the_title()the_excerpt() ,并添加HTML标记和the_ID() ,如下所示:

<?php
    if ( have_posts() ) : while ( have_posts() ): the_post(); ?>

    <div id="post-<?php the_ID(); ?>">
        <h2><?php the_title(); ?></h2>
        <div class="post-excerpt"><?php the_excerpt(); ?></div>
    </div>

    <?php endwhile;
    endif;
    ?>

We’ll now get a list of posts on our home page, with no style applied:

现在,我们将在我们的主页上获得帖子列表,但未应用任何样式:

Unstyled output

WordPress shows A blog page — an archive page for all the blog posts — by default.

WordPress默认显示一个博客页面(所有博客文章的存档页面)。

If we now visit single post URL — something like http://my-website.com/2018/11/14/sapiente-ad-facilis-quo-repellat-quos/ — we’ll see something like this:

如果现在访问单个帖子URL(例如http://my-website.com/2018/11/14/sapiente-ad-facilis-quo-repellat-quos/ ,我们将看到以下内容:

Our current single post layout

Our loop, albeit very crude, actually works.

我们的循环虽然很粗糙,但实际上有效。

将主题结构化为文件并应用Bootstrap标记 (Structuring Our Theme into Files and Applying Bootstrap Markup)

We’ll now implement partials, like header.php and footer.php and various specialized templates, all using Twitter Bootstrap markup, so that we can style it more easily.

现在,我们将使用Twitter Bootstrap标记来实现headers ,例如header.phpfooter.php以及各种专门的模板,以便我们可以更轻松地对其进行样式设置。

Starting with index.php, we replace all the content before and after the loop with get_header() and get_footer() functions:

index.php开始,我们用get_header()get_footer()函数替换循环前后的所有内容:

<?php
/**
 *
 * @package Botega_Scratch_Theme
 */

get_header(); ?>

    <?php
    if ( have_posts() ) : while ( have_posts() ): the_post(); ?>

    <div id="post-<?php the_ID(); ?>">
        <h2><?php the_title(); ?></h2>
        <div class="post-excerpt"><?php the_excerpt(); ?></div>
    </div>

    <?php endwhile;
    endif;
    ?>

<?php get_footer(); ?>

This means we need to provide all that content in the partials we mentioned.

这意味着我们需要在我们提到的部分内容中提供所有这些内容。

In line with what we said — that we’ll use Twitter Bootstrap theme — our header.php file will look like this:

符合我们所说的(我们将使用Twitter Bootstrap主题),我们的header.php文件将如下所示:

<?php
/**
 * The header for our theme.
 *
 * @package Botega_Scratch_Theme
 *
 */
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">

<?php wp_head(); ?>
</head>

<body <?php body_class(); ?>>

  <nav class="navbar navbar-default navbar-custom navbar-fixed-top">
    <div class="container-fluid">
      <div class="navbar-header page-scroll">
              <a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home" class="navbar-brand"><?php bloginfo( 'name' ); ?></a>
      </div>

      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
          <ul class="nav navbar-nav navbar-right">
          <?php wp_nav_menu( array( 'theme_location' => 'primary', 'items_wrap' => '%3$s' ) ); ?>
          </ul>
      </div>
    </div>
  </nav>

  <div class="container">
      <div class="row">

Our footer.php file will look like this:

我们的footer.php文件将如下所示:

<?php
/**
 * Footer template partial
 *
 * @package Botega_Scratch_Theme
 *
 */
?>
     </div>
     <!-- /.row -->
  </div>
  <!-- /.container -->

  <!-- Footer -->
  <footer>
    <div class="container">
      <div class="row">
          <div class="col-lg-8 col-md-10 mx-auto">
          </div>
      </div><!-- /.row -->
    </div><!-- /.container -->
  </footer><!-- /footer -->

<?php wp_footer(); ?>

</body>
</html>

We are using Bootstrap classes in our HTML tags, and wp_head() and wp_footer() fire wp_head and wp_footer action hooks.

我们在HTML标记中使用Bootstrap类,并且wp_head()wp_footer()触发wp_headwp_footer操作挂钩。

The next thing we’ll do is include the CSS and JavaScript from clean bootstrap template from startbootstrap.com, which comes with an MIT license, so we can freely use it. This way, our theme will come with predefined styles, responsiveness, and we’ll still be able to style it further.

接下来,我们将包括来自startbootstrap.com的干净启动模板CSS和JavaScript,该模板带有MIT许可证,因此我们可以自由使用它。 这样,我们的主题将具有预定义的样式,响应能力,并且我们仍然可以对其进行进一步的样式设置。

functions.php (functions.php)

functions.php is a file that comes with any serious WordPress theme. This is a file that acts as a poor man’s plugin archive. It allows us to include any custom functionality in our theme.

functions.php是任何严肃的WordPress主题附带的文件。 这是一个充当穷人的插件档案的文件。 它允许我们在主题中包含任何自定义功能。

We’ll firstly use this file to include Bootstrap and our bootstrap theme’s styles and scripts:

首先,我们将使用此文件包括Bootstrap以及bootstrap主题的样式和脚本:

function bsimple_scripts() {
    wp_enqueue_style( 'bsimple-style', get_stylesheet_uri() );
    wp_enqueue_style( 'bsimple-clean', get_template_directory_uri() . '/css/clean-blog.min.css' );
    wp_enqueue_style( 'bsimple-bootstrap', get_template_directory_uri() . '/css/bootstrap.min.css' );
    wp_enqueue_style( 'bsimple-fontawesome', get_template_directory_uri() . '/css/fa-all.min.css' );
    wp_enqueue_style( 'bsimple-font1', "https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic" );
    wp_enqueue_style( 'bsimple-font2', "https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" );

    wp_enqueue_script( 'bsimple-jq', get_template_directory_uri() . '/js/jquery.min.js');
    wp_enqueue_script( 'bsimple-bootstrap', get_template_directory_uri() . '/js/bootstrap.bundle.min.js');
    wp_enqueue_script( 'bsimple-clean', get_template_directory_uri() . '/js/clean-blog.min.js');
}    

add_action( 'wp_enqueue_scripts', 'bsimple_scripts' );

This is a WordPress-idiomatic way of including scripts and styles in a theme. It allows us to specify that the position of the scripts will be enqueued (header vs footer) and the priority of enqueuing. We can even specify the dependency of each particular resource on the other. This will ensure resources will be loaded in the right order.

这是一种WordPress惯用的方式,在主题中包括脚本和样式。 它允许我们指定将脚本的位置排入队列(页眉与页脚)以及排队的优先级。 我们甚至可以指定每个特定资源对另一个的依赖。 这将确保以正确的顺序加载资源。

We’re using the wp_enqueue_scripts action hook here. We can learn more about it in the Codex. (We covered action hooks in the previous article.)

我们在这里使用wp_enqueue_scripts操作钩子。 我们可以在食典中了解更多信息。 (我们在上一篇文章中介绍了动作挂钩。)

Inside our custom bsimple_scripts() function — which we hook to wp_enqueue_scripts action hook — we use two WordPress functions to load our scripts and styles — wp_enqueue_script() and wp_enqueue_style(). Arguments for these functions — as specified in its linked reference pages — allow us to fully leverage flexibility that we mentioned.

在我们自定义的bsimple_scripts()函数(我们将其钩到wp_enqueue_scripts操作钩)内部,我们使用两个WordPress函数来加载脚本和样式-wp_enqueue_script()wp_enqueue_style() 。 这些功能的参数(如其链接的参考页中所述)使我们能够充分利用我们提到的灵活性。

We can see that we’re loading styles from the Internet (Google fonts) and from our theme folder. Therefore, we create css, js and webfonts directories in our theme folder, and copy our Bootstrap theme’s CSS, JavaScript files, and FontAwesome icon-font files.

我们可以看到我们正在从Internet(Google字体)和主题文件夹中加载样式。 因此,我们在主题文件夹中创建cssjswebfonts目录,并复制Bootstrap主题CSS,JavaScript文件和FontAwesome图标字体文件。

We also copy our index.php file to archive.php, page.php and single.php files, which we’ll modify.

我们还将index.php文件复制到archive.phppage.phpsingle.php文件中,我们将对其进行修改。

Now our theme file structure will look something like this:

现在我们的主题文件结构将如下所示:

Our current theme file structure

调整标记 (Adjusting the Markup)

If we now visit our home page, we’ll see the menu on the top — though it and the page are still a mess – because the following line in our header is still outputting the menu wrapped in div and its own ul tags, so it isn’t affected by our bootstrap styles:

如果现在访问主页,我们将在顶部看到菜单(尽管它和页面仍然很混乱),因为标题中的以下行仍输出用div和自己的ul标签包装的菜单,因此它不受我们的引导程序样式的影响:

<?php wp_nav_menu( array( 'theme_location' => 'primary', 'items_wrap' => '%3$s' ) ); ?>

To solve this, we first need to go to our wp-admin dashboard and create — in the customizer — a new menu. we’ll name it Top Menu.

为了解决这个问题,我们首先需要转到wp-admin仪表板,并在定制程序中创建一个新菜单。 我们将其命名为Top Menu

After we’ve done this, we’ll go to our header.php file remove these lines:

完成此操作后,我们将转到header.php文件,删除以下header.php行:

<ul class="nav navbar-nav navbar-right">
<?php wp_nav_menu( array( 'theme_location' => 'primary', 'items_wrap' => '%3$s' ) ); ?>
</ul>

In their place we put these lines:

我们将这些行放在它们的位置:

<ul class="navbar-nav ml-auto">
    <?php wp_nav_menu(array(
      'menu' => 'Top Menu',
      'items_wrap'=>'%3$s',
      'container' => false,
      )); ?>
</ul>

This will remove the div tag and the duplication of the ul tag for us, but we still need to apply nav-item and nav-link to our menu items (to li and a tags respectively). How will we go about this? wp_nav_menu does not provide arguments for this. We’ll use the nav_menu_link_attributes and nav_menu_css_class filter hooks. We put this into our functions.php file:

这将删除div标签和的重复ul对我们的标签,但我们仍然需要应用nav-itemnav-link (向我们的菜单项lia分别标记)。 我们将如何处理? wp_nav_menu 不为此提供参数 。 我们将使用nav_menu_link_attributesnav_menu_css_class过滤器挂钩。 我们将其放入我们的functions.php文件中:

function add_menu_link_class( $atts, $item, $args ) {
    if($args->link_class) {
        $atts['class'] = $args->link_class;
    }
    return $atts;
}
add_filter( 'nav_menu_link_attributes', 'add_menu_link_class', 1, 3 );

function add_menu_list_item_class($classes, $item, $args) {
    if($args->list_item_class) {
        $classes[] = $args->list_item_class;
    }
    return $classes;
}
add_filter('nav_menu_css_class', 'add_menu_list_item_class', 1, 3);

Now we can specify new attributes in our wp_nav_menu in our header.php:

现在,我们可以在header.phpwp_nav_menu中指定新属性:

<ul class="navbar-nav ml-auto">
      <?php wp_nav_menu(array(
        'menu' => 'Top Menu',
        'items_wrap'=>'%3$s',
        'container' => false,
        'list_item_class' => "nav-item",
        'link_class' => "nav-link",
        )); ?>
</ul>

Now our top menu links can take advantage of styles already defined in our Bootstrap theme’s CSS.

现在,我们的顶级菜单链接可以利用Bootstrap主题CSS中已经定义的样式。

动态标题 (Dynamic Header)

To be able to use a dynamic header — that is, a different header for the front page, for other selected pages, or for archives — we’ll define a dynamic_header() function in our functions.php file, where we’ll output our header markup dependent on the page the visitor loads.

为了能够使用动态标头(即首页,其他选定页面或存档的不同标头dynamic_header() ,我们将在functions.php文件中定义dynamic_header()函数,在其中输出我们的标题标记取决于访问者加载的页面。

So now our header.php file will end like this:

所以现在我们的header.php文件将像这样结束:

</nav>

<?php dynamic_header(); ?>

<div class="container">
    <div class="row">

We’ll also define that function like this:

我们还将定义该函数,如下所示:

if(!function_exists('dynamic_header')){

function dynamic_header(){

    global $post;

    ?>

    <?php if (is_front_page()){ ?>

        <header class="masthead" style="background:#ccc;">
            <div class="overlay"></div>
            <div class="container">
                <div class="row">
                    <div class="col-lg-8 col-md-10 mx-auto">
                        <div class="site-heading">
                        <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
                        <span class="subheading"><?php get_bloginfo( 'description', 'display' );?></span>
                        </div>
                    </div>
                </div>
            </div>
        </header>

    <?php } else if (is_home()){ ?>

        <header class="masthead" style="background:#ccc;">
            <div class="overlay"></div>
            <div class="container">
                <div class="row">
                    <div class="col-lg-8 col-md-10 mx-auto">
                        <div class="site-heading">
                        <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
                        <span class="subheading"><?php get_bloginfo( 'description', 'display' );?></span>
                        </div>
                    </div>
                </div>
            </div>
        </header>

    <?php } else if (is_page()){ ?>

        <header class="masthead" style="background:#ccc;">
            <div class="overlay"></div>
            <div class="container">
                <div class="row">
                    <div class="col-lg-8 col-md-10 mx-auto">
                        <div class="site-heading">
                        <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
                        <span class="subheading"><?php get_bloginfo( 'description', 'display' );?></span>
                        </div>
                    </div>
                </div>
            </div>
        </header>

    <?php } else if (is_single()){ ?>

        <header class="masthead" style="background:#ccc;">
            <div class="overlay"></div>
            <div class="container">
                <div class="row">
                    <div class="col-lg-8 col-md-10 mx-auto">
                        <div class="site-heading">
                        <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
                        <span class="subheading"><?php get_bloginfo( 'description', 'display' );?></span>
                        </div>
                    </div>
                </div>
            </div>
        </header>

    <?php } else { ?>

        <header class="masthead" style="background:#ccc;">
            <div class="overlay"></div>
            <div class="container">
                <div class="row">
                    <div class="col-lg-8 col-md-10 mx-auto">
                        <div class="site-heading">
                        <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
                        <span class="subheading"><?php get_bloginfo( 'description', 'display' );?></span>
                        </div>
                    </div>
                </div>
            </div>
        </header>

    <?php }
}

}

To be able to use all the current URL or post data — like in the loop — we declare a $post variable global. Then we just fill different page or request cases with filler header HTML, which we’ll finish later. This sets the foundation for a truly dynamic header.

为了能够使用所有当前URL或发布数据(例如在循环中),我们声明一个$post变量global 。 然后,我们仅使用填充标头HTML填充不同的页面或请求案例,我们将在稍后完成。 这为真正的动态标头奠定了基础。

We need to make sure that our front page — with dynamic top menu — will look good even when the user is logged in. WordPress shows an admin bar when visitors are logged in, even when they visit the front page. Because it has position: fixed, it overlays the top zone on our website, covering whatever is there, so we need to specify an offset for our top menu.

我们需要确保即使用户登录后,带有动态顶部菜单的首页也将看起来不错。当访客登录时,即使他们访问首页,WordPress也会显示一个管理栏 。 因为它的position: fixed ,所以它覆盖了我们网站的顶部区域,覆盖了那里的所有内容,因此我们需要为顶部菜单指定一个偏移量。

We’ll add this to our style.css:

我们将其添加到我们的style.css

body.logged-in.admin-bar #mainNav {
    margin-top: 32px;
}

@media screen and (max-width: 782px) {
    body.logged-in.admin-bar #mainNav {
        margin-top: 46px;
    }
}

This makes sure the #mainNav — our menu container — has enough offset from the top, so it isn’t covered when user is logged in. WordPress adds logged-in and admin-bar classes to body in these cases, so we can easily target it.

这可以确保#mainNav (我们的菜单容器)与顶部之间有足够的偏移量,因此在用户登录时不会覆盖它。在这种情况下,WordPress将logged-inadmin-bar类添加到body中,因此我们可以轻松地进行操作。瞄准它。

We can see that we address two cases in our CSS — one default, and another one for smaller screens. This is because WordPress outputs a wider admin bar on mobile devices, so we need to provide a 46px offset.

我们可以看到我们在CSS中处理了两种情况-一种是默认情况,另一种是用于较小屏幕的情况。 这是因为WordPress在移动设备上输出了更宽的管理栏,因此我们需要提供46px的偏移量。

On mobile, we should now have a responsive, JavaScript-powered dropdown menu:

在移动设备上,我们现在应该有一个响应性的,基于JavaScript的下拉菜单:

Our dropdown on mobile

结论 (Conclusion)

In this second part on creating a WordPress theme from scratch, we created a very basic WordPress theme, and we included Bootstrap styles and scripts into it. We adjusted the menu output to fit our predefined styles. We also separated header and footer output into their respective partials.

在从头开始创建WordPress主题的第二部分中,我们创建了一个非常基本的WordPress主题,并且其中包含了Bootstrap样式和脚本。 我们调整了菜单输出以适合我们的预定义样式。 我们还将页眉和页脚输出分成各自的部分。

The functions.php file — a crucial file in theme development — is another topic we introduced and leveraged. Header output has been separated into its own function, which will use particulars of page visit, and site-owner–defined variables to determine the final output.

functions.php文件(在主题开发中至关重要的文件)是我们引入并利用的另一个主题。 标头输出已被分成自己的函数,该函数将使用页面访问的详细信息以及站点所有者定义的变量来确定最终输出。

In the third part of the guide, we’ll finish building particular templates, give better structure to our theme functions and partials, and finish up the styling of our website.

在指南的第三部分中,我们将完成特定模板的构建,为主题功能和部分提供更好的结构,并完成我们网站的样式。



There are three articles in this series on building a WordPress theme from scratch:

本系列中的三篇文章从头开始构建WordPress主题:

翻译自: https://www.sitepoint.com/build-wordpress-theme-from-scratch-basics/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值