Element-UI源码——Form表单

Form表单

form.vue

<template>
  <form class="el-form" :class="[
    labelPosition ? 'el-form--label-' + labelPosition : '',
    { 'el-form--inline': inline }
  ]">
    <slot></slot>
  </form>
</template>
<script>
  import objectAssign from 'element-ui/src/utils/merge';

  export default {
    name: 'ElForm',

    componentName: 'ElForm',
    // 将当前组件实例通过依赖注入的方式提供给后代
    // 后代可以通过inject访问elForm实例
    provide() {
      return {
        elForm: this
      };
    },
    props: {
      // 这些props大部分是给el-form-item使用的
      // 表单数据对象
      model: Object,
      // 表单验证规则
      rules: Object,
      // 表单域标签的位置,如果值为 left 或者 right 时,则需要设置 `label-width`
      labelPosition: String,
      // 表单域标签的宽度,例如 '50px'。作为 Form 直接子元素的 form-item 会继承该值。支持 `auto`。
      labelWidth: String,
      // 表单域标签的后缀
      labelSuffix: {
        type: String,
        default: ''
      },
      // 行内表单模式
      inline: Boolean,
      // 是否以行内形式展示校验信息
      inlineMessage: Boolean,
      // 是否在输入框中显示校验结果反馈图标
      statusIcon: Boolean,
      // 是否显示校验错误信息
      showMessage: {
        type: Boolean,
        default: true
      },
      // 用于控制该表单内组件的尺寸
      size: String,
      // 是否禁用该表单内的所有组件。若设置为 true,则表单内组件上的 disabled 属性不再生效
      disabled: Boolean,
      // 是否在 `rules` 属性改变后立即触发一次验证
      validateOnRuleChange: {
        type: Boolean,
        default: true
      },
      // 是否隐藏必填字段的标签旁边的红色星号
      hideRequiredAsterisk: {
        type: Boolean,
        default: false
      }
    },
    watch: {
      // 当rules发生变化时
      rules() {
        // remove then add event listeners on form-item after form rules change
        this.fields.forEach(field => {
          field.removeValidateEvents();
          field.addValidateEvents();
        });
           // 是否在 `rules` 属性改变后立即触发一次验证
        if (this.validateOnRuleChange) {
          this.validate(() => {});
        }
      }
    },
    computed: {
      autoLabelWidth() {
        if (!this.potentialLabelWidthArr.length) return 0;
        const max = Math.max(...this.potentialLabelWidthArr);
        return max ? `${max}px` : '';
      }
    },
    data() {
      return {
        fields: [],
        potentialLabelWidthArr: [] // use this array to calculate auto width
      };
    },
    created() {
      // 当el-form-item设置了prop时会触发emit el.form.addField事件 如下
      // this.dispatch('ElForm', 'el.form.addField', [this]);
      this.$on('el.form.addField', (field) => {
        if (field) {
          // 将el-form-item加入数组
          this.fields.push(field);
        }
      });
      /* istanbul ignore next */
      // 移除el-form-ite 在el-form-item销毁前会触发这个事件
      this.$on('el.form.removeField', (field) => {
        if (field.prop) {
          this.fields.splice(this.fields.indexOf(field), 1);
        }
      });
    },
    methods: {
      // 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
      resetFields() {
        if (!this.model) {
          console.warn('[Element Warn][Form]model is required for resetFields to work.');
          return;
        }
        // 遍历每个el-form-item调用其resetField方法
        this.fields.forEach(field => {
          field.resetField();
        });
      },
      // 清除表单验证
      clearValidate(props = []) {
        const fields = props.length
          ? (typeof props === 'string'
            ? this.fields.filter(field => props === field.prop)
            : this.fields.filter(field => props.indexOf(field.prop) > -1)
          ) : this.fields;
          // 调用el-form-item的清除表单验证
        fields.forEach(field => {
          field.clearValidate();
        });
      },
      // 表单验证
      validate(callback) {
        // 如果没有model会报警
        if (!this.model) {
          console.warn('[Element Warn][Form]model is required for validate to work!');
          return;
        }
        let promise;
        // if no callback, return promise
        // 如果没传递callback 会赋值一个 
        if (typeof callback !== 'function' && window.Promise) {
          promise = new window.Promise((resolve, reject) => {
            callback = function(valid, invalidFields) {
              valid ? resolve(valid) : reject(invalidFields);
            };
          });
        }
        // 为true表示验证通过
        let valid = true;
        let count = 0;
        // 如果需要验证的fields为空,调用验证时立刻返回callback
        if (this.fields.length === 0 && callback) {
          callback(true);
        }
        // 没有通过验证的field
        let invalidFields = {};
        this.fields.forEach(field => {
          // 遍历每个el-form-item调用其validate方法
          field.validate('', (message, field) => {
            // 如果有信息代表验证失败
            if (message) {
              valid = false;
            }
            // 添加没有验证通过的field
            invalidFields = objectAssign({}, invalidFields, field);
            // 如果存在回调函数并且每个field都验证了 触发callback回调传入验证结果和没有通过验证的field
            if (typeof callback === 'function' && ++count === this.fields.length) {
              callback(valid, invalidFields);
            }
          });
        });
        // 当没有传入回调函数时返回promise 
        if (promise) {
          return promise;
        }
      },
      // 对部分表单字段进行校验的方法
      validateField(props, cb) {
        props = [].concat(props);
        // 找到传入的props
        const fields = this.fields.filter(field => props.indexOf(field.prop) !== -1);
        if (!fields.length) {
          console.warn('[Element Warn]please pass correct props!');
          return;
        }
        // 单独验证 
        fields.forEach(field => {
          field.validate('', cb);
        });
      },
      getLabelWidthIndex(width) {
        const index = this.potentialLabelWidthArr.indexOf(width);
        // it's impossible
        if (index === -1) {
          throw new Error('[ElementForm]unpected width ', width);
        }
        return index;
      },
      registerLabelWidth(val, oldVal) {
        if (val && oldVal) {
          const index = this.getLabelWidthIndex(oldVal);
          this.potentialLabelWidthArr.splice(index, 1, val);
        } else if (val) {
          this.potentialLabelWidthArr.push(val);
        }
      },
      deregisterLabelWidth(val) {
        const index = this.getLabelWidthIndex(val);
        this.potentialLabelWidthArr.splice(index, 1);
      }
    }
  };
</script>

其中getPropByPath方法 根据路径查找Object属性下的值

export function getPropByPath(obj, path, strict) {
  let tempObj = obj;
  path = path.replace(/\[(\w+)\]/g, '.$1');
  path = path.replace(/^\./, '');
  // 分割出key
  let keyArr = path.split('.');
  let i = 0;
  // 遍历获取最后的值
  for (let len = keyArr.length; i < len - 1; ++i) {
    if (!tempObj && !strict) break;
    let key = keyArr[i];
    // 如果tempObj中有key 则将tempObj赋值为tempObj中key属性的值 然后继续向下找
    if (key in tempObj) {
      tempObj = tempObj[key];
    } else {
      if (strict) {
        throw new Error('please transfer a valid prop path to form item!');
      }
      break;
    }
  }
  // 最后返回 原来对象 key 和value值
  return {
    o: tempObj,
    k: keyArr[i],
    v: tempObj ? tempObj[keyArr[i]] : null
  };
};

Form Attributes

参数说明类型可选值默认值
model表单数据对象object
rules表单验证规则object
inline行内表单模式booleanfalse
label-position表单域标签的位置,如果值为 left 或者 right 时,则需要设置 label-widthstringright/left/topright
label-width表单域标签的宽度,例如 ‘50px’。作为 Form 直接子元素的 form-item 会继承该值。支持 autostring
label-suffix表单域标签的后缀string
hide-required-asterisk是否隐藏必填字段的标签旁边的红色星号booleanfalse
show-message是否显示校验错误信息booleantrue
inline-message是否以行内形式展示校验信息booleanfalse
status-icon是否在输入框中显示校验结果反馈图标booleanfalse
validate-on-rule-change是否在 rules 属性改变后立即触发一次验证booleantrue
size用于控制该表单内组件的尺寸stringmedium / small / mini
disabled是否禁用该表单内的所有组件。若设置为 true,则表单内组件上的 disabled 属性不再生效booleanfalse

Form Methods

方法名说明参数
validate对整个表单进行校验的方法,参数为一个回调函数。该回调函数会在校验结束后被调用,并传入两个参数:是否校验成功和未通过校验的字段。若不传入回调函数,则会返回一个 promiseFunction(callback: Function(boolean, object))
validateField对部分表单字段进行校验的方法Function(props: array | string, callback: Function(errorMessage: string))
resetFields对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
clearValidate移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组,如不传则移除整个表单的校验结果Function(props: array | string)

Form Events

事件名称说明回调参数
validate任一表单项被校验后触发被校验的表单项 prop 值,校验是否通过,错误消息(如果存在)

Form-item.vue

<template>
  <div class="el-form-item" :class="[{
      'el-form-item--feedback': elForm && elForm.statusIcon,
      'is-error': validateState === 'error',
      'is-validating': validateState === 'validating',
      'is-success': validateState === 'success',
      'is-required': isRequired || required,
      'is-no-asterisk': elForm && elForm.hideRequiredAsterisk
    },
    sizeClass ? 'el-form-item--' + sizeClass : ''
  ]">
    <label-wrap
      :is-auto-width="labelStyle && labelStyle.width === 'auto'"
      :update-all="form.labelWidth === 'auto'">
      <label :for="labelFor" class="el-form-item__label" :style="labelStyle" v-if="label || $slots.label">
        <slot name="label">{{label + form.labelSuffix}}</slot>
      </label>
    </label-wrap>
    <div class="el-form-item__content" :style="contentStyle">
      <slot></slot>
      <transition name="el-zoom-in-top">
         <!-- 自定义错误的具名插槽 可以像这种方式写 -->
        <!--<template v-slot:error=validateMessage>-->
          <!--<div>{{ validateMessage.error }}</div>-->
       <!--</template>-->
				 
        <slot
          v-if="validateState === 'error' && showMessage && form.showMessage"
          name="error"
          :error="validateMessage">
          <!-- 如果没有提供使用默认的错误显示方式 -->
          <div
            class="el-form-item__error"
            :class="{
              'el-form-item__error--inline': typeof inlineMessage === 'boolean'
                ? inlineMessage
                : (elForm && elForm.inlineMessage || false)
            }"
          >
            {{validateMessage}}
          </div>
        </slot>
      </transition>
    </div>
  </div>
</template>
<script>
// 对数据进行异步校验的库
  import AsyncValidator from 'async-validator';
  import emitter from 'element-ui/src/mixins/emitter';
  import objectAssign from 'element-ui/src/utils/merge';
  import { noop, getPropByPath } from 'element-ui/src/utils/util';
  import LabelWrap from './label-wrap';
  export default {
    name: 'ElFormItem',
    componentName: 'ElFormItem',
    mixins: [emitter],
    provide() {
      return {
        elFormItem: this
      };
    },
    inject: ['elForm'],
    props: {
      // 标签文本
      label: String,
      // 表单域标签的的宽度,例如 '50px'。支持 auto。
      labelWidth: String,
      // 表单域 model 字段,在使用 validate、resetFields 方法的情况下,该属性是必填的
      prop: String,
      // 是否必填,如不设置,则会根据校验规则自动生成
      required: {
        type: Boolean,
        default: undefined
      },
      // 表单验证规则
      rules: [Object, Array],
      // 表单域验证错误信息, 设置该值会使表单验证状态变为error,并显示该错误信息
      error: String,
      // 验证状态
      validateStatus: String,
      for: String,
      // 以行内形式展示校验信息
      inlineMessage: {
        type: [String, Boolean],
        default: ''
      },
      // 是否显示校验错误信息
      showMessage: {
        type: Boolean,
        default: true
      },
      // 用于控制该表单域下组件的尺寸
      size: String
    },
    components: {
      // use this component to calculate auto width
      LabelWrap
    },
    watch: {
      error: {
        immediate: true,
        handler(value) {
          this.validateMessage = value;
          this.validateState = value ? 'error' : '';
        }
      },
      validateStatus(value) {
        this.validateState = value;
      },
      rules(value) {
        if ((!value || value.length === 0) && this.required === undefined) {
          this.clearValidate();
        }
      }
    },
    computed: {
      labelFor() {
        return this.for || this.prop;
      },
      labelStyle() {
        const ret = {};
        if (this.form.labelPosition === 'top') return ret;
        const labelWidth = this.labelWidth || this.form.labelWidth;
        if (labelWidth) {
          ret.width = labelWidth;
        }
        return ret;
      },
      contentStyle() {
        const ret = {};
        const label = this.label;
        if (this.form.labelPosition === 'top' || this.form.inline) return ret;
        if (!label && !this.labelWidth && this.isNested) return ret;
        const labelWidth = this.labelWidth || this.form.labelWidth;
        if (labelWidth === 'auto') {
          if (this.labelWidth === 'auto') {
            ret.marginLeft = this.computedLabelWidth;
          } else if (this.form.labelWidth === 'auto') {
            ret.marginLeft = this.elForm.autoLabelWidth;
          }
        } else {
          ret.marginLeft = labelWidth;
        }
        return ret;
      },
      form() {
        let parent = this.$parent;
        let parentName = parent.$options.componentName;
        while (parentName !== 'ElForm') {
          if (parentName === 'ElFormItem') {
            this.isNested = true;
          }
          parent = parent.$parent;
          parentName = parent.$options.componentName;
        }
        return parent;
      },
      // 字段的值
      fieldValue() {
        // 获取form传入的model对象
        const model = this.form.model;
        if (!model || !this.prop) { return; }
        // 获取prop传入的路径
        let path = this.prop;
        // 将:替代成.
        if (path.indexOf(':') !== -1) {
          path = path.replace(/:/, '.');
        }
        // 在element-ui/src/utils/util中定义的方法 根据路径查找Object属性下的值
        return getPropByPath(model, path, true).v;
      },
      // 是否为必填项
      isRequired() {
        // 获取当前el-form-item的校验规则
        let rules = this.getRules();
        let isRequired = false;
        if (rules && rules.length) {
          // 去规则里面找required 找到了就给isRequired设置为true表示是否为必填项
          rules.every(rule => {
            if (rule.required) {
              isRequired = true;
              // 找到了就退出
              return false;
            }
            // 找不到继续遍历
            return true;
          });
        }
        return isRequired;
      },
      // elform的尺寸大小
      _formSize() {
        return this.elForm.size;
      },
      // elform的尺寸大小 自己有设置自己的 没有找elform上的尺寸
      elFormItemSize() {
        return this.size || this._formSize;
      },
      sizeClass() {
        return this.elFormItemSize || (this.$ELEMENT || {}).size;
      }
    },
    data() {
      return {
        // 验证状态
        validateState: '',
        // 验证信息
        validateMessage: '',
        // ?
        validateDisabled: false,
        validator: {},
        isNested: false,
        computedLabelWidth: ''
      };
    },
    methods: {
      // noop是空对象
      validate(trigger, callback = noop) {
        // 验证没有被禁用 
        this.validateDisabled = false;
        // 根据trigger过滤规则
        const rules = this.getFilteredRule(trigger);

        if ((!rules || rules.length === 0) && this.required === undefined) {
          callback();
          return true;
        }
        // 正在验证中 
        this.validateState = 'validating';

        const descriptor = {};
        // 先将trigger属性删除
        if (rules && rules.length > 0) {
          rules.forEach(rule => {
            delete rule.trigger;
          });
        }
        descriptor[this.prop] = rules;
        // {属性prop:[{},{}]}
        const validator = new AsyncValidator(descriptor);
        const model = {};

        model[this.prop] = this.fieldValue;
        // {属性prop:属性值}
        // 参数
        // 1.要验证的对象
        // 2.验证处理选项 firstFields是否在指定字段的第一个规则验证错误时调用回调,不再处理相同字段的验证规则
        // 3.验证完成时调用的回调
        validator.validate(model, { firstFields: true }, (errors, invalidFields) => {
          this.validateState = !errors ? 'success' : 'error';
          this.validateMessage = errors ? errors[0].message : '';
          // 调用回调函数
          callback(this.validateMessage, invalidFields);
          // 触发elform上绑定的validate方法 任一表单项被校验后触发
          this.elForm && this.elForm.$emit('validate', this.prop, !errors, this.validateMessage || null);
        });
      },
      // 移除该表单项的校验结果
      clearValidate() {
        this.validateState = '';
        this.validateMessage = '';
        this.validateDisabled = false;
      },
      // 对该表单项进行重置,将其值重置为初始值并移除校验结果
      resetField() {
        this.validateState = '';
        this.validateMessage = '';

        let model = this.form.model;
        let value = this.fieldValue;
        let path = this.prop;
        if (path.indexOf(':') !== -1) {
          path = path.replace(/:/, '.');
        }

        let prop = getPropByPath(model, path, true);
        // 验证禁用
        this.validateDisabled = true;
        if (Array.isArray(value)) {
          prop.o[prop.k] = [].concat(this.initialValue);
        } else {
          prop.o[prop.k] = this.initialValue;
        }

        // reset validateDisabled after onFieldChange triggered
        this.$nextTick(() => {
          this.validateDisabled = false;
        });
        // 找到子节点中的时间选择器 设置初始值
        this.broadcast('ElTimeSelect', 'fieldReset', this.initialValue);
      },
      // 获取规则
      getRules() {
        // 从form中获取校验规则
        let formRules = this.form.rules;
        const selfRules = this.rules;
        // 如果传入了required 则设置当前required值 否则设置为一个空数组
        const requiredRule = this.required !== undefined ? { required: !!this.required } : [];
        // 去formRules对象中找出路径 prop对应的规则 找不到设置为''
        const prop = getPropByPath(formRules, this.prop || '');
        // 如果form中的规则存在 将formRules设为上面的规则prop规则 否则设置为空数组
        formRules = formRules ? (prop.o[this.prop || ''] || prop.v) : [];
        // 如果当前el-form-item传入了规则置为当前 否则设置为从form中找到的规则 最后如果还找不到就设置空数组
        return [].concat(selfRules || formRules || []).concat(requiredRule);
      },
      // 规律规则
      getFilteredRule(trigger) {
        // 获取规则
        const rules = this.getRules();
        // 从规则中过滤 
        // 1.规则没有触发条件或者触发条件为空
        // 2.从规则中可以找出与之对应的触发条件
        return rules.filter(rule => {
          if (!rule.trigger || trigger === '') return true;
          if (Array.isArray(rule.trigger)) {
            return rule.trigger.indexOf(trigger) > -1;
          } else {
            return rule.trigger === trigger;
          }
        }).map(rule => objectAssign({}, rule));
      },
      // 监听blur事件
      onFieldBlur() {
        this.validate('blur');
      },
      // 监听change事件
      onFieldChange() {
        // 如果被禁用了则取消禁用
        if (this.validateDisabled) {
          this.validateDisabled = false;
          return;
        }
        this.validate('change');
      },
      updateComputedLabelWidth(width) {
        this.computedLabelWidth = width ? `${width}px` : '';
      },
      // 添加验证事件
      addValidateEvents() {
        // 获取当前规则
        const rules = this.getRules();
        // 当规则变化后根据是否包含当前字段判断是否加上blur和change事件
        if (rules.length || this.required !== undefined) {
          this.$on('el.form.blur', this.onFieldBlur);
          this.$on('el.form.change', this.onFieldChange);
        }
      },
      // 移除自身的事件
      removeValidateEvents() {
        // 移除自定义事件监听器。
        // 如果没有提供参数,则移除所有的事件监听器;
        // 如果只提供了事件,则移除该事件所有的监听器;
        // 如果同时提供了事件与回调,则只移除这个回调的监听器。
        this.$off();
      }
    },
    mounted() {
      // 如果prop存在
      if (this.prop) {
        // 调用父组件el-form内的el.form.addField事件
        this.dispatch('ElForm', 'el.form.addField', [this]);
          // 记录初始值
        let initialValue = this.fieldValue;
        if (Array.isArray(initialValue)) {
          initialValue = [].concat(initialValue);
        }
        // 无法修改的初始值为了重置表单使用
        Object.defineProperty(this, 'initialValue', {
          value: initialValue
        });
        // 添加验证事件
        this.addValidateEvents();
      }
    },
    // 销毁组件之前触发form中的el.form.removeField事件将自己移除
    beforeDestroy() {
      this.dispatch('ElForm', 'el.form.removeField', [this]);
    }
  };
</script>

Form-Item Attributes

参数说明类型可选值默认值
prop表单域 model 字段,在使用 validate、resetFields 方法的情况下,该属性是必填的string传入 Form 组件的 model 中的字段
label标签文本string
label-width表单域标签的的宽度,例如 ‘50px’。支持 autostring
required是否必填,如不设置,则会根据校验规则自动生成booleanfalse
rules表单验证规则object
error表单域验证错误信息, 设置该值会使表单验证状态变为error,并显示该错误信息string
show-message是否显示校验错误信息booleantrue
inline-message以行内形式展示校验信息booleanfalse
size用于控制该表单域下组件的尺寸stringmedium / small / mini-

Form-Item Slot

name说明
Form Item 的内容
label标签文本的内容

Form-Item Scoped Slot

name说明
error自定义表单校验信息的显示方式,参数为 { error }

Form-Item Methods

方法名说明参数
resetField对该表单项进行重置,将其值重置为初始值并移除校验结果-
clearValidate移除该表单项的校验结果
  • 38
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Element-UIform 表单是一种基于Vue.jsUI 组件,它包含了一系列表单元素,允许你快速创建表单,并且支持表单验证。它还提供了一些特殊的表单元素,如日期选择器和文件上传等,可以帮助你构建出更加复杂的表单界面。 ### 回答2: Element-UI是一套基于Vue.js的桌面端组件库,其中form表单是其中一个常用的组件之一。Element-UIform表单提供了方便易用的表单创建和验证工具,能够快速地创建出美观、灵活的表单界面。 Element-UIform表单具有多种表单项类型,例如文本输入框、选择框、日期选择器等,能够满足各种不同类型的表单需求。同时,Element-UI还提供了规则验证机制,可以对表单进行必填项验证、长度验证等,保证用户输入的有效性。此外,Element-UIform表单还支持表单布局的设置,可以通过配置参数实现单列、多列等不同的布局方式,适应不同的界面布局需求。 在使用Element-UIform表单时,只需要在Vue.js的组件中引入form表单组件并进行配置,即可快速创建出一个完整的表单页面。开发者只需要设置表单项的类型和验证规则等参数,Element-UI会自动根据配置渲染出相应的表单界面,并对用户输入的内容进行验证。而且,Element-UIform表单还支持表单响应式的设计,能够根据不同设备的宽度进行自适应调整,确保在不同分辨率的屏幕上都能正常显示。 总之,Element-UI中的form表单是一个功能强大、使用方便的组件,可以快速创建出各种类型的表单界面,并提供了灵活的验证机制和布局设置,帮助开发者提高开发效率。 ### 回答3: element-ui 中的 form 表单是一个用于收集和验证用户输入信息的组件。它提供了丰富的表单元素和验证规则,方便开发者进行表单的设计和数据校验。 首先,element-uiform 表单可以用来创建各种表单元素,如输入框、下拉框、单选框、多选框等等。开发者可以根据需要选择合适的表单元素,并设置其属性、样式和事件。 其次,element-uiform 表单支持数据校验,可以通过设定验证规则来确保用户输入的数据的有效性。验证规则可以是内置的常见规则,如必填、最大长度、最小值等,也可以是自定义的规则。当用户提交表单时,element-ui 会自动验证表单的字段,并对不符合规则的字段进行提示。 此外,element-uiform 表单还提供了一些特殊功能。例如,可以自定义表单校验提示信息的样式和位置;可以配置表单的布局方式,如水平布局、垂直布局等;还可以设置表单的禁用状态,使其变为只读或不可编辑状态。 总的来说,element-uiform 表单是一个强大且易用的表单组件,可以满足开发者在设计表单和实现数据校验时的需求。通过使用 form 表单,开发者可以减少开发时间和工作量,提高用户体验和数据的准确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值