二次封装el-form--只需配置文件

本文介绍如何使用Vue3和Element Plus库进行表单组件的二次封装,提供了一个具体的配置文件实例,并展示了组件内部的实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 兄弟们经过我上班摸鱼,最近摸了很多组件,一点点分享给大家。大佬们就别看了,二次封装很简单哦。我是根据element+封装的。大家在封装时,根据文档的api一步步实现。我给大家说说简单的思路。具体代码请看:https://gitee.com/liu--zicheng/vue3-vite-template/blob/master/src/components/ui/ZcForm.vue

其中也有table封装,包括搜索栏一键生成0。 

 <el-form-item label="Password" prop="pass">
      <el-input v-model="ruleForm.pass" type="password" autocomplete="off" />
    </el-form-item>
    <el-form-item label="Confirm" prop="checkPass">
      <el-input
        v-model="ruleForm.checkPass"
        type="password"
        autocomplete="off"
      />
    </el-form-item>

根据上面代码,大家来找相同的部分,然后通过配置的形式传入即可,是不是很简单。下面给大家分享我的配置文件。

 

import { formConfig } from "./../../../config/formConfig";

export const FormConfig = formConfig({
  formItems: [
    {
      label: "表单1",
      type: "number",
      otherOptions: {
        placeholder: "请输入账号",
      },
      prop: "account",
      rules: [
        {
          required: true,
          message: "请输入账号",
          trigger: "change",
        },
        {
          validator: (rule, value, callback) => {
            console.log("....", typeof value);
            if (value.length < 3 && value.length > 1) {
              callback(new Error("请输入长度大于3"));
            }
          },
          trigger: "change",
        },
      ],
    },
    {
      label: "表单2",
      type: "password",
      prop: "password",
      otherOptions: {
        placeholder: "请输入密码",
      },
      rules: [{ required: true, message: "请输入密码" }],
    },
    {
      label: "表单3",
      type: "datepicker",
      otherOptions: {
        startPlaceholder: "开始时间",
        endPlaceholder: "结束时间",
        type: "daterange",
        "unlink-panels": true,
        // disabled: true,
      },
      prop: "date",
      rules: [{ required: true, message: "请选择日期" }],
    },

    {
      label: "表单4",
      type: "select",
      otherOptions: {
        placeholder: "请选择部门",
        clearable: true,
        multiple: true,
      },
      prop: "dep",
      valueEnum: {
        1: "部门1",
        2: "部门2",
        3: "部门3",
        4: "部门4",
        5: "部门5",
        6: "部门6",
      },
      rules: [{ required: true, message: "请选择", trigger: "blur" }],
      width: 100,
    },
  ],
  labelWidth: "100px",
  //   itemColLayout: {
  //     // span: 8,
  //   },
  //   itemStyle: {
  //     padding: "",
  //   },
});

 这个配置文件,组件不需要动,除非有情况没有考虑,或者代码不严谨。大家可以根据情况书写自己的组件。

然后看看组件内部写法。

 

<template>
  <el-form ref="ruleFormRef" :model="form" :label-width="labelWidth">
    <el-row>
      <template v-for="item in formItems">
        <el-col v-bind="itemColLayout">
          <el-form-item
            :label="item.label"
            :prop="item.prop"
            :style="itemStyle"
            :rules="item.rules"
          >
            <el-input
              v-if="item.type == 'number'"
              v-model="form[`${item.prop}`]"
              :type="item.type"
              v-bind="item.otherOptions"
              onkeypress="return /[\d]/.test(String.fromCharCode(event.keyCode))"
            />
            <el-input
              v-if="item.type == 'input' || item.type == 'password'"
              v-model="form[`${item.prop}`]"
              :type="item.type"
              :show-password="item.type === 'password'"
              v-bind="item.otherOptions"
            />
            <el-select
              v-if="item.type == 'select'"
              v-model="form[`${item.prop}`]"
              v-bind="item.otherOptions"
              style="width: 100%"
            >
              <el-option
                v-for="option in item.valueEnum"
                :key="option"
                :label="item.valueEnum[option]"
                :value="option"
              ></el-option>
            </el-select>

            <el-date-picker
              v-if="item.type == 'datepicker'"
              v-model="form[`${item.prop}`]"
              v-bind="item.otherOptions"
            ></el-date-picker>
          </el-form-item>
        </el-col>
      </template>
    </el-row>
    <div class="footer">
      <slot name="footer">
        <el-button type="primary" @click="resetBtnClick">重置</el-button>
        <el-button type="primary" @click="searchBtnClick(ruleFormRef)"
          >提交</el-button
        >
      </slot>
    </div>
  </el-form>
</template>

<script setup lang="ts">
import { RuleItem } from "async-validator";
import { FormInstance } from "element-plus";
import { StyleValue } from "vue";
const ruleFormRef = ref<FormInstance>();
interface FormItems {
  label?: string;
  type?: string;
  placeholder?: string;
  rules?: RuleItem;
  prop?: string;
  valueEnum?: Object;
  clearable?: boolean;
  disabled?: boolean;
  multiple?: boolean;
  width?: number;
  otherOptions?: any;
}
const props = withDefaults(
  defineProps<{
    formItems: Array<FormItems | any>;
    labelWidth?: string;
    itemColLayout?: object;
    itemStyle?: StyleValue;
    request?: any;
  }>(),
  {
    labelWidth: "120px",
    itemColLayout: () => ({
      xl: 6, // >=1920px
      lg: 8, // >=1200px
      md: 12, // >=992px
      sm: 24, // >=768px
      xs: 24, // <768px
    }),
    itemStyle: () => ({
      padding: "0",
    }),
  }
);
const formParams = computed(() => {
  let params: any = {};
  props.formItems.map((item) => {
    params[item.prop] = "";
  });
  return params;
});
const form = reactive({ ...formParams.value });

// 提交按钮
const searchBtnClick = async (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  await formEl.validate((valid, fields) => {
    if (valid) {
      console.log("submit!", form);
      props.request(form);
    } else {
      console.log("error submit!", valid, fields);
    }
  });
};
// 重置按钮
const resetBtnClick = () => {
  ruleFormRef.value?.resetFields();
};
</script>

<style scoped lang="scss">
.footer {
  text-align: right;
}
</style>

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>问卷管理系统 - Vue3 + Element Plus</title> <link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css"> <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script> <script src="https://unpkg.com/element-plus/dist/index.full.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif; background-color: #f5f7fa; color: #333; padding: 20px; } .container { max-width: 1400px; margin: 0 auto; background: #fff; border-radius: 8px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); padding: 25px; } .header { text-align: center; margin-bottom: 30px; padding-bottom: 20px; border-bottom: 1px solid #ebeef5; } .header h1 { color: #409EFF; font-size: 28px; margin-bottom: 10px; } .header p { color: #909399; font-size: 16px; } /* 顶部索引板块 - 桌面端垂直布局 */ .filter-container .el-form-item { margin-bottom: 22px; } .filter-container .el-form-item__label { display: block; text-align: left; padding: 0 0 8px 0; float: none; } .filter-container .el-form-item__content { margin-left: 0 !important; width: 100%; } .filter-container .el-select, .filter-container .el-input { width: 100%; } .search-btn-container { display: flex; justify-content: flex-end; margin-top: 10px; } .table-container { margin-top: 30px; } .pagination-container { margin-top: 20px; display: flex; justify-content: flex-end; } /* 移动端响应式优化 */ @media (max-width: 768px) { .container { padding: 15px; } .el-form-item { margin-bottom: 15px; } .el-form-item__label { float: none; display: block; text-align: left; padding: 0 0 8px 0; } .el-form-item__content { margin-left: 0 !important; } .mobile-full-width { width: 100%; } .el-select { width: 100%; } .search-btn-container { flex-direction: column; gap: 10px; } .search-btn-container .el-button { margin-left: 0 !important; } } .status-tag { padding: 4px 8px; border-radius: 4px; font-size: 12px; } .status-0 { background: #f0f9eb; color: #67c23a; } .status-1 { background: #ecf5ff; color: #409eff; } .status-2 { background: #fdf6ec; color: #e6a23c; } .status-3 { background: #fef0f0; color: #f56c6c; } .loading-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255, 255, 255, 0.7); display: flex; align-items: center; justify-content: center; z-index: 10; } </style> </head> <body> <div id="app"> <div class="container"> <div class="header"> <h1>问卷管理系统</h1> <p>响应式详情页面 - 顶部索引与分页展示</p> </div> <!-- 顶部索引板块 --> <div class="filter-container"> <el-form :model="searchForm"> <!-- 问卷标题搜索 --> <el-form-item label="问卷标题"> <el-input v-model="searchForm.title" placeholder="输入问卷标题" clearable /> </el-form-item> <!-- 被测评人ID搜索 --> <el-form-item label="被测评人ID"> <el-input v-model="searchForm.userId" placeholder="输入被测评人ID" clearable /> </el-form-item> <!-- 部门选择 --> <el-form-item label="人员部门"> <el-select v-model="searchForm.dept" placeholder="选择部门" clearable > <el-option label="技术部" value="tech"></el-option> <el-option label="市场部" value="market"></el-option> <el-option label="人力资源部" value="hr"></el-option> <el-option label="财务部" value="finance"></el-option> <el-option label="产品部" value="product"></el-option> </el-select> </el-form-item> <!-- 状态选择 --> <el-form-item label="提交状态"> <el-select v-model="searchForm.status" placeholder="选择状态" clearable > <el-option label="未提交" value="0"></el-option> <el-option label="已提交" value="1"></el-option> <el-option label="审核中" value="2"></el-option> <el-option label="已完成" value="3"></el-option> </el-select> </el-form-item> <!-- 搜索按钮 --> <div class="search-btn-container"> <el-button type="primary" @click="handleSearch" icon="el-icon-search" class="mobile-full-width" :loading="loading" >搜索</el-button> <el-button type="info" @click="resetForm" icon="el-icon-refresh" class="mobile-full-width" >重置</el-button> <el-button type="success" @click="exportData" icon="el-icon-download" class="mobile-full-width" >导出数据</el-button> </div> </el-form> </div> <!-- 数据表格 --> <div class="table-container" v-loading="loading"> <el-table :data="tableData" border style="width: 100%"> <el-table-column prop="id" label="ID" width="80" /> <el-table-column prop="title" label="问卷标题" min-width="150" /> <el-table-column prop="userId" label="被测评人ID" width="120" /> <el-table-column prop="dept" label="部门" width="120"> <template #default="scope"> {{ formatDept(scope.row.dept) }} </template> </el-table-column> <el-table-column prop="status" label="状态" width="100"> <template #default="scope"> <span :class="['status-tag', `status-${scope.row.status}`]"> {{ formatStatus(scope.row.status) }} </span> </template> </el-table-column> <el-table-column prop="createTime" label="创建时间" width="180" /> <el-table-column prop="updateTime" label="更新时间" width="180" /> <el-table-column label="操作" width="120"> <template #default="scope"> <el-button size="mini" @click="handleEdit(scope.row)">查看</el-button> </template> </el-table-column> </el-table> <!-- 无数据提示 --> <div v-if="tableData.length === 0 && !loading" class="el-table__empty-block"> <span class="el-table__empty-text">暂无数据</span> </div> </div> <!-- 分页组件 --> <div class="pagination-container"> <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="total" :page-sizes="[10, 20, 50, 100]" :page-size="pageSize" :current-page="currentPage" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> </div> </div> <script> const { createApp, ref, reactive, computed, onMounted } = Vue; const app = createApp({ setup() { // 搜索表单数据 const searchForm = reactive({ title: '', userId: '', dept: '', status: '' }); // 表格数据 const tableData = ref([]); // 分页数据 const total = ref(0); const pageSize = ref(10); const currentPage = ref(1); // 加载状态 const loading = ref(false); // 部门格式化 const formatDept = (dept) => { const deptMap = { tech: '技术部', market: '市场部', hr: '人力资源部', finance: '财务部', product: '产品部' }; return deptMap[dept] || dept; }; // 状态格式化 const formatStatus = (status) => { const statusMap = { '0': '未提交', '1': '已提交', '2': '审核中', '3': '已完成' }; return statusMap[status] || status; }; // 获取表格数据 const fetchTableData = async () => { try { loading.value = true; // 构造请求参数 const params = { ...searchForm, page: currentPage.value, size: pageSize.value }; // 在实际项目中,这里应该调用真实API // const response = await axios.get('http://172.26.26.43/dev-api/wjdc/wj/listTx', { params }); // 模拟API延迟 await new Promise(resolve => setTimeout(resolve, 800)); // 模拟API响应 const mockData = { total: 85, data: Array.from({ length: pageSize.value }, (_, i) => ({ id: i + 1 + (currentPage.value - 1) * pageSize.value, title: `问卷${i + 1}`, userId: `USER${1000 + i}`, dept: ['tech', 'market', 'hr', 'finance', 'product'][i % 5], status: String(i % 4), createTime: '2023-06-01 10:00:00', updateTime: '2023-06-01 14:30:00' })) }; // 更新数据 tableData.value = mockData.data; total.value = mockData.total; } catch (error) { console.error('获取数据失败:', error); } finally { loading.value = false; } }; // 搜索操作 const handleSearch = () => { currentPage.value = 1; // 重置到第一页 fetchTableData(); }; // 重置表单 const resetForm = () => { Object.keys(searchForm).forEach(key => { searchForm[key] = ''; }); currentPage.value = 1; fetchTableData(); }; // 分页大小改变 const handleSizeChange = (size) => { pageSize.value = size; fetchTableData(); }; // 当前页改变 const handleCurrentChange = (page) => { currentPage.value = page; fetchTableData(); }; // 导出数据 const exportData = () => { ElMessage.success('导出功能已触发,在实际项目中会调用导出API'); console.log('导出参数:', searchForm); }; // 编辑操作 const handleEdit = (row) => { ElMessage.info(`查看问卷: ${row.title}`); console.log('查看问卷数据:', row); }; // 初始化时加载数据 onMounted(() => { fetchTableData(); }); return { searchForm, tableData, total, pageSize, currentPage, loading, formatDept, formatStatus, handleSearch, resetForm, handleSizeChange, handleCurrentChange, exportData, handleEdit }; } }); app.use(ElementPlus); app.mount('#app'); </script> </body> </html> 帮我修改代码,写到.vue文件里
07-15
<template> <el-form ref="ruleFormRef" style="margin-top: 20px;max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto" :disabled="pageMode === 'view'"> <el-form-item label="产品名称:" prop="name"> <el-input v-model="ruleForm.name" /> </el-form-item> <el-form-item label="产品描述:" prop="description"> <el-input v-model="ruleForm.description" type="textarea"/> </el-form-item> <el-form-item label="产品分类:" prop="category" style="width: 50%;"> <el-select v-model="ruleForm.category" placeholder="请选择分类"> <el-option v-for="item in categorys" :label="item.name" :value="item.id" :key="item.id" /> </el-select> </el-form-item> <el-form-item label="产品单价:" prop="price"> <el-input v-model.number="ruleForm.price" type="number" style="width: 240px" /> </el-form-item> <el-form-item label="产品库存:" prop="stock"> <el-input v-model.number="ruleForm.stock" type="number" style="width: 240px" /> </el-form-item> <el-form-item label="生产厂家:" prop="manufacturer"> <el-input v-model="ruleForm.manufacturer" /> </el-form-item> <el-form-item label="产地:" required> <el-col :span="12"> <el-form-item prop="originProvince"> <el-select v-model="ruleForm.originProvince" placeholder="省" style="flex: 1; margin-right: 10px"> <el-option v-for="item in originProvinces" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item prop="originCity"> <el-select v-model="ruleForm.originCity" placeholder="市" style="flex: 1 " :disabled="!ruleForm.originProvince"> <el-option v-for="item in originCitys" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> </el-col> </el-form-item> <el-form-item label="发货地:" required> <el-col :span="12"> <el-form-item prop="shippingProvince"> <el-select v-model="ruleForm.shippingProvince" placeholder="省" style="flex: 1; margin-right: 10px"> <el-option v-for="item in originProvinces" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item prop="shippingCity"> <el-select v-model="ruleForm.shippingCity" placeholder="市" style="flex: 1" :disabled="!ruleForm.shippingProvince"> <el-option v-for="item in shippingCities" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> </el-col> </el-form-item> <el-form-item label="生产日期" required> <el-col :span="11"> <el-form-item prop="createAt"> <el-date-picker v-model="ruleForm.createAt" type="date" aria-label="Pick a date" placeholder="Pick a date" style="width: 100%" /> </el-form-item> </el-col> </el-form-item> <el-form-item> <!-- 登录按钮:仅在默认模式下显示 --> <el-button v-if="pageMode === 'default'" style="margin-left: 18px;" type="primary" @click="submitForm(ruleFormRef, ruleForm)"> 登录 </el-button> <!-- 更新按钮:仅在编辑模式下显示 --> <el-button v-if="pageMode === 'edit'" style="margin-left: 30px;" type="primary" @click="updateForm(ruleFormRef)"> 更新 </el-button> <!-- 重置按钮:在编辑或默认模式下都显示 --> <el-button v-if="pageMode === 'edit' || pageMode === 'default'" style="margin-left: 30px;" type="primary" @click="resetForm(ruleFormRef)"> 重置 </el-button> </el-form-item> </el-form> </template> <script setup> import { ref, reactive, onMounted } from 'vue'; import productApi from '@/api/products' import placeApi from '@/api/place' import { useRouter } from 'vue-router' import { ElLoading, ElMessage } from 'element-plus' const pageMode = ref('') // 可选值: 'view', 'edit', 'default' const router = useRouter(); const ruleFormRef = ref() const categorys = ref([])// 产品分类 const originProvinces = ref([]) // 省份数据 const originCitys = ref([]) // 城市数据 const shippingCities = ref([]) // 发货地城市数据 const ruleForm = reactive({ name: '', description: '', category: '', price: '', stock: '', manufacturer: '', originProvince: '', originCity: '', shippingProvince: '', shippingCity: '', createAt: '', user: 'aaa', delivery: false, type: [], }) const rules = reactive({ name: [ { required: true, message: '请输入产品名称', trigger: 'blur' }, { max: 10, message: '长度超过10位', trigger: 'blur' }, ], description: [ { required: true, message: '请输入产品描述', trigger: 'blur' }, { max: 200, message: '长度超过200位', trigger: 'blur' }, ], category: [ { required: true, message: '请选择产品分类', trigger: 'change', }, ], price: [ { required: true, message: '请输入产品单价', trigger: ['blur', 'change'] }, { validator: (rule, value, callback) => { if (value === null || value === '') { callback(new Error('请输入产品单价')) } else if (value <= 0) { callback(new Error('单价必须大于 0')) } else if (value > 10000) { callback(new Error('单价不能大于 10000')) } else { callback() } }, trigger: ['blur', 'change'] } ], stock: [ { required: true, message: '请输入产品库存', trigger: ['blur', 'change'] }, { validator: (rule, value, callback) => { if (value === null || value === '') { callback(new Error('请输入商品单价')) } else if (value <= 0) { callback(new Error('单价必须大于 0')) } else if (value > 10000) { callback(new Error('单价不能大于 10000')) } else { callback() } }, trigger: ['blur', 'change'] } ], manufacturer: [ { required: true, message: '请输入生产厂家', trigger: 'blur' }, ], originProvince: { validator: (rule, value, callback) => { if (!value) { callback(new Error('请选择产地省份')) } else { callback() } }, trigger: 'change' }, originCity:{ validator: (rule, value, callback) => { if (!value) { callback(new Error('请选择产地城市')) } else { callback() } }, trigger: 'change' }, shippingProvince: { validator: (rule, value, callback) => { if (!value) { callback(new Error('请选择发货省份')) } else { callback() } }, trigger: 'change' }, shippingCity:{ validator: (rule, value, callback) => { if (!value) { callback(new Error('请选择发货城市')) } else { callback() } }, trigger: 'change' }, createAt: [ { type: 'date', required: true, message: '请输入日期', trigger: 'change', }, ], }) // 重置表单操作 const resetForm = (formEl) => { if (!formEl) return formEl.resetFields() } //产品分类 function getCategory() { productApi.getCategory().then(res => { categorys.value = res.data; }) } // 获取商品详情 function getProductDetail(productId) { productApi.getById(productId).then(res => { const data = res.data // 先赋值整个对象 Object.assign(ruleForm, data) }).catch(error => { console.error('获取商品详情失败:', error); }); } // 获取省份 function getProvinces() { placeApi.getProvince().then(res => { originProvinces.value = res.data }).catch(error => { console.error('获取省份失败:', error) }) } // 监听产地省份变化,加载城市 watch( () => ruleForm.originProvince, (newVal) => { if (newVal) { placeApi.getCity(newVal).then(res => { originCitys.value = res.data }).catch(() => { originCitys.value = [] }) } else { // 如果省份为空,则清空城市列表和当前选中的城市字段 originCitys.value = [] ruleForm.originCity = '' } } ) // 监听发货地省份变化,加载城市 watch( () => ruleForm.shippingProvince, (newVal) => { if (newVal) { placeApi.getCity(newVal).then(res => { shippingCities.value = res.data }).catch(() => { shippingCities.value = [] }) } else { // 如果省份为空,则清空城市列表和当前选中的城市字段 shippingCities.value = [] ruleForm.shippingCity = '' } } ) // 更新操作 const updateForm = async (formEl) => { if (!formEl) return const loading = ElLoading.service({ fullscreen: true }) await formEl.validate((valid, fields) => { if (valid) { console.log('开始提交...') // 调用 API 更新商品信息 productApi.update(ruleForm).then(res => { ElMessage.success('更新成功') router.push('/home/test1') // 可选跳转回列表页 }).catch(error => { console.error('更新失败:', error) ElMessage.error('更新失败,请重试') }).finally(() => { loading.close() }) } else { console.log('表单验证失败:', fields) ElMessage.error('请检查输入内容') loading.close() return false } }) } // 登录操作 const submitForm = async (formEl, ruleForm) => { if (!formEl) return await formEl.validate((valid, fields) => { if (valid) { console.log('开始提交商品...') const loading = ElLoading.service({ fullscreen: true }) productApi.addProduct(ruleForm).then(res => { ElMessage.success('登录成功') router.push('/home/test1') }).catch(error => { console.error('登录失败:', error) ElMessage.error('登录失败,请重试') }).finally(() => { loading.close() }) } else { console.log('表单验证失败:', fields) ElMessage.error('请检查输入内容') loading.close() return false } }) } onMounted(() => { getCategory() getProvinces() // 获取当前路由信息 const route = router.currentRoute.value // 判断页面是查看、编辑还是新增模式 const type = route.query.type const productId = route.params.id || route.query.id if (type === 'view') { pageMode.value = 'view' // 查看模式:不显示按钮 } else if (type === 'edit') { pageMode.value = 'edit' // 编辑模式:显示“更新”、“重置” } else { pageMode.value = 'default' // 默认模式:显示“登录”、“重置” } // 如果存在商品 ID,则调用接口获取商品详情并填充表单 if (productId) { getProductDetail(productId) } }) </script> <style> .location-selectors { display: flex; justify-content: space-between; width: 100%; } </style> 我想将form表单拆分成五层自定义组件结构
最新发布
07-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

成序猿@

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

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

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

打赏作者

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

抵扣说明:

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

余额充值