MVVM架构的介绍和使用

一、什么是 MVVM 架构

MVVM 全称:Model – View – ViewModel;属于 UI 架构模式之一。
核心目标:解耦 UI 和 业务逻辑,通过数据绑定 (Binding) 实现 UI 自动更新。

三层职责对比:
在这里插入图片描述
CSV:MVVM 运行流程 (强绑定)

用户输入 → View → 绑定 → ViewModel → 更新 Model → 更新 ViewModel 属性 → 自动刷新界面

特点:ViewModel 中数据变化 → UI 自动更新,无需手动调用 setText()

为什么 MVVM 适用于 Qt?
Qt 的框架天生支持:
在这里插入图片描述
因此:

  • Qt QML = 完整 MVVM
  • Qt Widgets = 稍弱 MVVM(手动绑定)

二、MVVM的优缺点

MVVM 的优势
在这里插入图片描述
MVVM 的劣势
在这里插入图片描述
适合长生命周期项目或复杂界面

三、Qt 下 MVVM 示例结构

以“加减乘除计算器”为例:

+---------------------+
|        View         | ← UI LineEdit/Button/Label
+---------------------+
            ↑   ↓ (绑定)
+---------------------+
|     ViewModel       | ← Q_PROPERTY、信号槽、命令按钮
+---------------------+
            ↑   ↓
+---------------------+
|       Model         | ← 纯业务逻辑
+---------------------+

一个简单的实际例子(伪代码说明)
Model

double add(double a, double b);

ViewModel → 暴露 Q_PROPERTY

Q_PROPERTY(double operandA READ operandA WRITE setOperandA NOTIFY operandAChanged)
Q_PROPERTY(double result READ result NOTIFY resultChanged)

当 operandA 改变

setOperandA()Model::calculate() → 更新 result → emit resultChanged → UI自动刷新

View(Widgets)

connect(lineEditA, textChanged => ViewModel::setOperandA)
connect(ViewModel::resultChanged => label->setText(...))
  • UI 不直接操作业务逻辑
  • ViewModel 不知道 UI 存在

四、MVC 与 MVVM 的比较

MVC vs MVVM
在这里插入图片描述
结构职责对比
在这里插入图片描述
本质区别
在这里插入图片描述
优点 vs 缺点
MVC
优点:

  • 结构简单、易理解
  • 小项目开发快速

缺点:

  • Controller 容易越来越臃肿
  • UI 更新逻辑分散在各处
  • 模块复用性弱

MVVM
优点:

  • UI 自动更新(减少 setText 等 UI 控制代码)
  • 逻辑脱耦彻底,可复用
  • ViewModel 可单元测试
  • 大型项目可维护性增强

缺点:

  • 初期设计成本更高
  • 双向绑定不当会出现循环风险
  • 对开发者要求更高(特别是 Qt Widgets)

应用场景选型建议
在这里插入图片描述

五、完整示例

支持加减乘除,可直接使用的计算器 MVVM 示例
示例分成三层:

  • Model(纯业务逻辑)
  • ViewModel(UI 逻辑 + 绑定)
  • View(界面,使用 ViewModel,不访问内部变量)

所有成员变量都 private,公开接口均通过 Q_PROPERTY / 方法 / 信号,符合 Qt MVVM 最佳实践。

1.Model 层(纯业务:加、减、乘、除)

// CalculatorModel.h
#pragma once
#include <QObject>

class CalculatorModel : public QObject {
    Q_OBJECT
public:
    explicit CalculatorModel(QObject* parent = nullptr)
        : QObject(parent) {}

    double add(double a, double b)     { return a + b; }
    double sub(double a, double b)     { return a - b; }
    double mul(double a, double b)     { return a * b; }
    double div(double a, double b)     { return b != 0 ? a / b : 0; }
};
  • Model 层没有 UI,也没有信号槽,只处理 纯数学逻辑。
  • 成员变量全封装。

2.ViewModel 层(UI 绑定与行为逻辑)
通过 Q_PROPERTY 绑定 UI,让 UI 自动收到 ViewModel 的状态改变。

// CalculatorViewModel.h
#pragma once

#include <QObject>
#include "CalculatorModel.h"

class CalculatorViewModel : public QObject {
    Q_OBJECT

    Q_PROPERTY(double result READ result NOTIFY resultChanged)

public:
    explicit CalculatorViewModel(QObject* parent = nullptr)
        : QObject(parent), m_model(new CalculatorModel(this)) {}

    double result() const { return m_result; }

public slots:
    void calculateAdd(double a, double b) {
        m_result = m_model->add(a, b);
        emit resultChanged();
    }

    void calculateSub(double a, double b) {
        m_result = m_model->sub(a, b);
        emit resultChanged();
    }

    void calculateMul(double a, double b) {
        m_result = m_model->mul(a, b);
        emit resultChanged();
    }

    void calculateDiv(double a, double b) {
        m_result = m_model->div(a, b);
        emit resultChanged();
    }

signals:
    void resultChanged();

private:
    CalculatorModel* m_model;  // 完全封装,不暴露
    double m_result = 0;       // 绑定变量
};

特点:

  • m_model 与 m_result 完全私有
  • View 层无法直接访问内部变量
  • UI 会自动通过 Q_PROPERTY 收到更新
  • 所有业务都通过 public slots() 执行

符合 MVVM 的标准模式:

View → 调用 ViewModel 方法 → ViewModel 调用 Model → 更新结果 → 发射信号 → View 刷新 UI

3.View 层(Qt Widgets 版本示例)
View 只操作 ViewModel 的公开接口,不访问其内部变量。

// CalculatorWindow.h
#pragma once

#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include "CalculatorViewModel.h"

class CalculatorWindow : public QWidget {
    Q_OBJECT
public:
    explicit CalculatorWindow(CalculatorViewModel* vm, QWidget* parent = nullptr)
        : QWidget(parent), m_vm(vm)
    {
        m_a = new QLineEdit(this);
        m_b = new QLineEdit(this);
        m_result = new QLineEdit(this);
        m_result->setReadOnly(true);

        auto btnAdd = new QPushButton("加", this);
        auto btnSub = new QPushButton("减", this);
        auto btnMul = new QPushButton("乘", this);
        auto btnDiv = new QPushButton("除", this);

        connect(btnAdd, &QPushButton::clicked, this, &CalculatorWindow::onAdd);
        connect(btnSub, &QPushButton::clicked, this, &CalculatorWindow::onSub);
        connect(btnMul, &QPushButton::clicked, this, &CalculatorWindow::onMul);
        connect(btnDiv, &QPushButton::clicked, this, &CalculatorWindow::onDiv);

        // View绑定 ViewModel 的结果
        connect(m_vm, &CalculatorViewModel::resultChanged, this, [this]() {
            m_result->setText(QString::number(m_vm->result()));
        });
    }

private slots:
    void onAdd() { m_vm->calculateAdd(a(), b()); }
    void onSub() { m_vm->calculateSub(a(), b()); }
    void onMul() { m_vm->calculateMul(a(), b()); }
    void onDiv() { m_vm->calculateDiv(a(), b()); }

private:
    double a() const { return m_a->text().toDouble(); }
    double b() const { return m_b->text().toDouble(); }

    CalculatorViewModel* m_vm;

    QLineEdit* m_a;
    QLineEdit* m_b;
    QLineEdit* m_result;
};

4.图示:MVVM 调用链

[View] 按钮点击
      ↓   调用
[ViewModel] calculateAdd()
      ↓   调用
[Model] add(a, b)[ViewModel] 设置 m_result → emit resultChanged()[View] 监听 resultChanged() → 更新界面

MVVM(Model–View–ViewModel)架构 + Q_PROPERTY + 自动绑定
1.设计图(MVVM)

         +----------------------+
         |      View(UI)      |
         | QML/Widget,只做绑定 |
         +-----------+----------+
                     |
                  Binding
                     |
         +-----------v----------+
         |   ViewModel (逻辑)   |
         | Q_PROPERTY, signal   |
         +-----------+----------+
                     |
                   调用
                     |
         +-----------v----------+
         |      Model(数据)     |
         |  真正的计算逻辑      |
         +----------------------+

2.Model(数据 + 计算逻辑,不暴露成员)

// CalculatorModel.h
#pragma once
#include <QObject>

class CalculatorModel : public QObject
{
    Q_OBJECT

public:
    explicit CalculatorModel(QObject* parent=nullptr);

    double add(double a, double b) const;
    double sub(double a, double b) const;
    double mul(double a, double b) const;
    double div(double a, double b, bool& ok) const;
};
// CalculatorModel.cpp
#include "CalculatorModel.h"

CalculatorModel::CalculatorModel(QObject* parent)
    : QObject(parent)
{
}

double CalculatorModel::add(double a, double b) const { return a + b; }
double CalculatorModel::sub(double a, double b) const { return a - b; }
double CalculatorModel::mul(double a, double b) const { return a * b; }

double CalculatorModel::div(double a, double b, bool& ok) const
{
    if (b == 0) { ok = false; return 0; }
    ok = true;
    return a / b;
}

3. ViewModel(MVVM 核心:对外暴露 Q_PROPERTY)
核心:ViewModel 维护 a、b、result 的状态,View 通过绑定自动更新。

// CalculatorViewModel.h
#pragma once
#include <QObject>

class CalculatorModel;

class CalculatorViewModel : public QObject
{
    Q_OBJECT

    Q_PROPERTY(double operandA READ operandA WRITE setOperandA NOTIFY operandAChanged)
    Q_PROPERTY(double operandB READ operandB WRITE setOperandB NOTIFY operandBChanged)
    Q_PROPERTY(double result   READ result   NOTIFY resultChanged)

public:
    explicit CalculatorViewModel(CalculatorModel* model,
                                 QObject* parent=nullptr);

    // 属性读写
    double operandA() const;
    double operandB() const;
    double result() const;

    void setOperandA(double v);
    void setOperandB(double v);

public slots:
    void add();
    void sub();
    void mul();
    void div();

signals:
    void operandAChanged();
    void operandBChanged();
    void resultChanged();

private:
    CalculatorModel* m_model;

    double m_a = 0;
    double m_b = 0;
    double m_result = 0;

    void updateResult(double r);
};
// CalculatorViewModel.cpp
#include "CalculatorViewModel.h"
#include "CalculatorModel.h"

CalculatorViewModel::CalculatorViewModel(
        CalculatorModel* model,
        QObject* parent)
    : QObject(parent)
    , m_model(model)
{
}

double CalculatorViewModel::operandA() const { return m_a; }
double CalculatorViewModel::operandB() const { return m_b; }
double CalculatorViewModel::result() const { return m_result; }

void CalculatorViewModel::setOperandA(double v)
{
    if (m_a == v) return;
    m_a = v;
    emit operandAChanged();
}

void CalculatorViewModel::setOperandB(double v)
{
    if (m_b == v) return;
    m_b = v;
    emit operandBChanged();
}

void CalculatorViewModel::updateResult(double r)
{
    if (m_result == r) return;
    m_result = r;
    emit resultChanged();
}

void CalculatorViewModel::add()
{
    updateResult(m_model->add(m_a, m_b));
}

void CalculatorViewModel::sub()
{
    updateResult(m_model->sub(m_a, m_b));
}

void CalculatorViewModel::mul()
{
    updateResult(m_model->mul(m_a, m_b));
}

void CalculatorViewModel::div()
{
    bool ok;
    double r = m_model->div(m_a, m_b, ok);
    updateResult(r);
}

4. View(UI 层)

// CalculatorView.h
#pragma once
#include <QWidget>

class CalculatorViewModel;
class QLineEdit;
class QPushButton;

class CalculatorView : public QWidget
{
    Q_OBJECT
public:
    explicit CalculatorView(CalculatorViewModel* vm,
                            QWidget* parent=nullptr);

private:
    CalculatorViewModel* m_vm;
};
// CalculatorView.cpp
#include "CalculatorView.h"
#include "CalculatorViewModel.h"

#include <QGridLayout>
#include <QLineEdit>
#include <QPushButton>

CalculatorView::CalculatorView(CalculatorViewModel* vm,
                               QWidget* parent)
    : QWidget(parent)
    , m_vm(vm)
{
    auto editA = new QLineEdit(this);
    auto editB = new QLineEdit(this);
    auto editR = new QLineEdit(this);
    editR->setReadOnly(true);

    auto btnAdd = new QPushButton("+");
    auto btnSub = new QPushButton("-");
    auto btnMul = new QPushButton("*");
    auto btnDiv = new QPushButton("/");

    auto layout = new QGridLayout(this);
    layout->addWidget(editA, 0, 0, 1, 2);
    layout->addWidget(editB, 1, 0, 1, 2);
    layout->addWidget(editR, 2, 0, 1, 2);

    layout->addWidget(btnAdd, 3, 0);
    layout->addWidget(btnSub, 3, 1);
    layout->addWidget(btnMul, 4, 0);
    layout->addWidget(btnDiv, 4, 1);

    // UI → ViewModel
    connect(editA, &QLineEdit::textChanged,
            this, [=](const QString& t){ m_vm->setOperandA(t.toDouble()); });

    connect(editB, &QLineEdit::textChanged,
            this, [=](const QString& t){ m_vm->setOperandB(t.toDouble()); });

    // ViewModel → UI
    connect(m_vm, &CalculatorViewModel::resultChanged,
            this, [=]{ editR->setText(QString::number(m_vm->result())); });

    // 操作→VM 触发计算
    connect(btnAdd, &QPushButton::clicked, m_vm, &CalculatorViewModel::add);
    connect(btnSub, &QPushButton::clicked, m_vm, &CalculatorViewModel::sub);
    connect(btnMul, &QPushButton::clicked, m_vm, &CalculatorViewModel::mul);
    connect(btnDiv, &QPushButton::clicked, m_vm, &CalculatorViewModel::div);
}

完全基于 Signal + Slot 绑定的 MVVM 版本
总设计(Signal/Slot MVVM)

 View(UI) 
       ▲       (UI 绑定 ViewModel)
       | signals/slots
 ViewModel(逻辑)
       ▲       (ViewModel 驱动 Model)
       |
      Model(业务逻辑)

1.Model(只做计算,不保存 UI 状态)

// CalculatorModel.h
#pragma once
#include <QObject>

class CalculatorModel : public QObject
{
    Q_OBJECT
public:
    explicit CalculatorModel(QObject* parent=nullptr);

public slots:
    double add(double a, double b) const;
    double sub(double a, double b) const;
    double mul(double a, double b) const;
    double div(double a, double b, bool& ok) const;
};
// CalculatorModel.cpp
#include "CalculatorModel.h"

CalculatorModel::CalculatorModel(QObject* parent)
    : QObject(parent)
{
}

double CalculatorModel::add(double a, double b) const { return a + b; }
double CalculatorModel::sub(double a, double b) const { return a - b; }
double CalculatorModel::mul(double a, double b) const { return a * b; }

double CalculatorModel::div(double a, double b, bool& ok) const
{
    if (b == 0) { ok = false; return 0; }
    ok = true;
    return a / b;
}

2. ViewModel(绑定层,用信号驱动计算)
ViewModel 不直接访问 UI,只维护数据状态,并通过信号广播结果。

// CalculatorViewModel.h
#pragma once
#include <QObject>

class CalculatorModel;

class CalculatorViewModel : public QObject
{
    Q_OBJECT

public:
    explicit CalculatorViewModel(CalculatorModel* model,
                                 QObject* parent=nullptr);

public slots:
    void setOperandA(double v);
    void setOperandB(double v);

    void requestAdd();
    void requestSub();
    void requestMul();
    void requestDiv();

signals:
    void resultChanged(double v);

private:
    CalculatorModel* m_model;
    double m_a = 0;
    double m_b = 0;
};
// CalculatorViewModel.cpp
#include "CalculatorViewModel.h"
#include "CalculatorModel.h"

CalculatorViewModel::CalculatorViewModel(
        CalculatorModel* model,
        QObject* parent)
    : QObject(parent)
    , m_model(model)
{
}

void CalculatorViewModel::setOperandA(double v)
{
    m_a = v;
}

void CalculatorViewModel::setOperandB(double v)
{
    m_b = v;
}

void CalculatorViewModel::requestAdd()
{
    emit resultChanged(m_model->add(m_a, m_b));
}

void CalculatorViewModel::requestSub()
{
    emit resultChanged(m_model->sub(m_a, m_b));
}

void CalculatorViewModel::requestMul()
{
    emit resultChanged(m_model->mul(m_a, m_b));
}

void CalculatorViewModel::requestDiv()
{
    bool ok;
    double r = m_model->div(m_a, m_b, ok);
    emit resultChanged(r);
}

3. View(UI 部分,完全使用 signal/slot 绑定 ViewModel)
View 不做任何计算,只负责输入与显示。

// CalculatorView.h
#pragma once
#include <QWidget>

class CalculatorViewModel;
class QLineEdit;
class QPushButton;

class CalculatorView : public QWidget
{
    Q_OBJECT
public:
    explicit CalculatorView(CalculatorViewModel* vm,
                            QWidget* parent=nullptr);

private:
    CalculatorViewModel* m_vm;
};
// CalculatorView.cpp
#include "CalculatorView.h"
#include "CalculatorViewModel.h"

#include <QLineEdit>
#include <QPushButton>
#include <QGridLayout>

CalculatorView::CalculatorView(CalculatorViewModel* vm,
                               QWidget* parent)
    : QWidget(parent)
    , m_vm(vm)
{
    auto editA = new QLineEdit();
    auto editB = new QLineEdit();
    auto editR = new QLineEdit();
    editR->setReadOnly(true);

    auto btnAdd = new QPushButton("+");
    auto btnSub = new QPushButton("-");
    auto btnMul = new QPushButton("*");
    auto btnDiv = new QPushButton("/");

    auto layout = new QGridLayout(this);
    layout->addWidget(editA, 0, 0, 1, 2);
    layout->addWidget(editB, 1, 0, 1, 2);
    layout->addWidget(editR, 2, 0, 1, 2);

    layout->addWidget(btnAdd, 3, 0);
    layout->addWidget(btnSub, 3, 1);
    layout->addWidget(btnMul, 4, 0);
    layout->addWidget(btnDiv, 4, 1);

    //
    // ----------- UI → ViewModel -----------
    //
    connect(editA, &QLineEdit::textChanged,
            this, [=](const QString& txt){
                m_vm->setOperandA(txt.toDouble());
            });

    connect(editB, &QLineEdit::textChanged,
            this, [=](const QString& txt){
                m_vm->setOperandB(txt.toDouble());
            });

    //
    // ----------- ViewModel → UI -----------
    //
    connect(m_vm, &CalculatorViewModel::resultChanged,
            this, [=](double v){
                editR->setText(QString::number(v));
            });

    //
    // ----------- 按钮触发计算 -----------
    //
    connect(btnAdd, &QPushButton::clicked, m_vm, &CalculatorViewModel::requestAdd);
    connect(btnSub, &QPushButton::clicked, m_vm, &CalculatorViewModel::requestSub);
    connect(btnMul, &QPushButton::clicked, m_vm, &CalculatorViewModel::requestMul);
    connect(btnDiv, &QPushButton::clicked, m_vm, &CalculatorViewModel::requestDiv);
}

MVVM + 双向绑定 Qt Widgets 示例
功能说明(双向绑定):
在这里插入图片描述
关键:避免无限循环,例如 LineEdit → ViewModel → LineEdit 更新 → 再触发输入回。我们使用 信号阻断器 + 值比较 防止递归更新。

1.Model(业务逻辑)

// CalculatorModel.h
#pragma once

class CalculatorModel
{
public:
    double calculate(double a, double b, char op)
    {
        switch(op) {
        case '+': return a + b;
        case '-': return a - b;
        case '*': return a * b;
        case '/': return (b != 0) ? a / b : 0;
        default: return 0;
        }
    }
};

2.ViewModel(Q_PROPERTY + 绑定)

// CalculatorViewModel.h
#pragma once
#include <QObject>
#include "CalculatorModel.h"

class CalculatorViewModel : public QObject
{
    Q_OBJECT
    Q_PROPERTY(double operandA READ operandA WRITE setOperandA NOTIFY operandAChanged)
    Q_PROPERTY(double operandB READ operandB WRITE setOperandB NOTIFY operandBChanged)
    Q_PROPERTY(double result READ result NOTIFY resultChanged)
    Q_PROPERTY(char op READ op WRITE setOp NOTIFY opChanged)

public:
    explicit CalculatorViewModel(QObject* parent=nullptr)
        : QObject(parent) {}

    double operandA() const { return m_operandA; }
    double operandB() const { return m_operandB; }
    double result() const   { return m_result; }
    char op() const         { return m_op; }

public slots:
    void setOperandA(double v) {
        if (qFuzzyCompare(m_operandA, v)) return;
        m_operandA = v;
        emit operandAChanged(v);
        updateResult();
    }

    void setOperandB(double v) {
        if (qFuzzyCompare(m_operandB, v)) return;
        m_operandB = v;
        emit operandBChanged(v);
        updateResult();
    }

    void setOp(char o) {
        if (m_op == o) return;
        m_op = o;
        emit opChanged(o);
        updateResult();
    }

signals:
    void operandAChanged(double);
    void operandBChanged(double);
    void resultChanged(double);
    void opChanged(char);

private:
    void updateResult() {
        double newResult = m_model.calculate(m_operandA, m_operandB, m_op);
        if (!qFuzzyCompare(m_result, newResult)) {
            m_result = newResult;
            emit resultChanged(m_result);
        }
    }

private:
    CalculatorModel m_model;
    double m_operandA = 0;
    double m_operandB = 0;
    double m_result = 0;
    char m_op = '+';
};

3.View(界面及双向绑定逻辑)

// CalculatorView.h
#pragma once
#include <QWidget>
#include <QLineEdit>
#include <QLabel>
#include <QComboBox>
#include <QHBoxLayout>
#include "CalculatorViewModel.h"

class CalculatorView : public QWidget
{
    Q_OBJECT
public:
    explicit CalculatorView(CalculatorViewModel* vm, QWidget* parent=nullptr)
        : QWidget(parent), m_vm(vm)
    {
        auto layout = new QHBoxLayout(this);

        m_editA = new QLineEdit("0", this);
        m_opBox = new QComboBox(this);
        m_editB = new QLineEdit("0", this);
        m_labelResult = new QLabel("= 0", this);

        m_opBox->addItems({"+", "-", "*", "/"});

        layout->addWidget(m_editA);
        layout->addWidget(m_opBox);
        layout->addWidget(m_editB);
        layout->addWidget(m_labelResult);

        bindViewToVM();
        bindVMToView();
    }

private:
    void bindViewToVM()
    {
        connect(m_editA, &QLineEdit::textChanged, this, [this](const QString& text){
            m_vm->setOperandA(text.toDouble());
        });
        connect(m_editB, &QLineEdit::textChanged, this, [this](const QString& text){
            m_vm->setOperandB(text.toDouble());
        });
        connect(m_opBox, &QComboBox::currentTextChanged, this, [this](const QString& op){
            m_vm->setOp(op[0].toLatin1());
        });
    }

    void bindVMToView()
    {
        connect(m_vm, &CalculatorViewModel::operandAChanged, this, [this](double v){
            QSignalBlocker blocker(m_editA);
            m_editA->setText(QString::number(v));
        });
        connect(m_vm, &CalculatorViewModel::operandBChanged, this, [this](double v){
            QSignalBlocker blocker(m_editB);
            m_editB->setText(QString::number(v));
        });
        connect(m_vm, &CalculatorViewModel::opChanged, this, [this](char o){
            QSignalBlocker blocker(m_opBox);
            int idx = m_opBox->findText(QString(o));
            if (idx >= 0) m_opBox->setCurrentIndex(idx);
        });
        connect(m_vm, &CalculatorViewModel::resultChanged, this, [this](double r){
            m_labelResult->setText("= " + QString::number(r));
        });
    }

private:
    CalculatorViewModel* m_vm;

    QLineEdit* m_editA;
    QComboBox* m_opBox;
    QLineEdit* m_editB;
    QLabel* m_labelResult;
};

4.Main(启动程序)

// main.cpp
#include <QApplication>
#include "CalculatorView.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    CalculatorViewModel vm;
    CalculatorView view(&vm);
    view.show();

    return app.exec();
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值