前端如何封装一个组件?怎么造轮子?手写js封装一个dialog弹窗组件。

Element Plus 入门:从零搭一个管理后台 前端开发中经常提到组件库,组件库有哪些优点? 阅读详情

一、现在要你完成一个Dialog组件,说说你设计的思路?它应该有什么功能?

以前没有尝试过封装组件,其实也没有严格意义的去笼统的学习过封装组件,最近使用layui满频繁的,想要封装一个dialog,尝试一下自己去动手封装一个组件,锻炼一下自己的动手能力,当然在这里也是分享给大家。

回到上方我们其实可以回想一下大体的功能,如果是一个弹窗的话,我们应该怎样去调用?应该怎么去使用呢?是使用js api来调用,还是说放置一个已经写好的html模板,让其设置display:none? js 手动将其显示?

其实上面的问题,我们可以参照一下layui和bootstrap

首先我们可以先看一下bootstrap的弹窗组件
在这里插入图片描述

在这里插入图片描述

我们其实可以明显的看出在bootstrap中其实也就是手动的将html标签语句放置在了body体内,而layui其实就是将对应的弹窗封装成了一个js文件,当调用时,去调用这个js文件的方法,然后采用插入节点的方式,将弹窗呈现。

那么我们应该去采用哪种方式来封装这个弹窗呢?在这里的话我们就将其手动的写入到js文件当中,让其使用js api的方式,让弹窗跳出,从而实现效果。

大体功能

  • 该组件需要提供hook指定渲染位置,默认渲染在body下面。
  • 然后改组件可以指定外层样式,如宽度等
  • 组件外层还需要一层mask来遮住底层内容,点击mask可以执行传进来的onCancel函数关闭Dialog。
  • 另外组件是可控的,需要外层传入visible表示是否可见。
  • 然后Dialog可能需要自定义头head和底部footer,默认有头部和底部,底部有一个确认按钮和取消按钮,确认按钮会执行外部传进来的onOk事件,然后取消按钮会执行外部传进来的onCancel事件。
  • 组件高度可能大于页面高度,组件内部需要滚动条。

我略微的删减掉了几个功能,因为我们采用的是像layui 式js的跳出方式,所以我们不需要 对应的变量去控制对应的展示还是隐藏,所以我们的dialog需要实现的就是上方的几个功能。

二、文档结构

在这里插入图片描述
我们大体需要3个文件,一个css、一个html、一个js文件

三、样式Css文件

/*index.css*/
*{
  margin:0;
  padding:0;
}
/* a标签去除下划线改变颜色 */
a{
  text-decoration: none;
  color: black;
}
/* 弹窗容器 */
.keyui-dialog-box{
  width: 100vw;
  height: 100vh;
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 100000;
}
/* 遮罩层样式 */
.keyui-masking-layer{
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .3);
}
/* 弹窗默认样式 */
.keyui-dialog{
  width:50vw;
  height:50vh;
  background-color: white;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%,-50%);
}
/* 头部设置固定高度 */
.keyui-dialog-head{
  width: 100%;
  height: 40px;
  line-height: 40px;
  padding: 0 20px;
  box-sizing: border-box;
  background-color: #f8f8f8;
  border-bottom: 1px solid #eeeeee;
  position: relative;
}
/* 右上角关闭图标 */
.keyui-rightUp-close{
  position: absolute;
  right: 20px;
}
/* 弹窗内容区域 */
.keyui-dialog-content{
  height: calc(100% - 40px);
  padding: 20px;
  box-sizing: border-box;
  overflow-y: auto;  /* 为什么要设置auto,因为内容区域有时会超出弹窗大小 */
}
/* btn按钮样式 */
.keyui-btn {
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  background: #FFF;
  border: 1px solid #DCDFE6;
  color: #606266;
  -webkit-appearance: none;
  text-align: center;
  box-sizing: border-box;
  outline: 0;
  margin: 0;
  -webkit-transition: .1s;
  transition: .1s;
  font-weight: 500;
  padding: 12px 20px;
  font-size: 14px;
  border-radius: 4px; 
}
/* 鼠标移入按钮效果 */
.keyui-btn:hover {
  color: #409eff;
  border-color: #c6e2ff;
  background-color: #ecf5ff;
}
/* 确认按钮 */
.keyui-btn-primary {
  color: #FFF;
  background-color: #409EFF;
  border-color: #409EFF;
}
/* 确认按钮鼠标移入效果 */
.keyui-btn-primary:hover {
  background: #66b1ff;
  border-color: #fff;
  color: #fff;
}
/* 确认按钮mini样式 */
.keyui-btn-mini {
  font-size: 12px;
  border-radius: 3px;
  padding: 7px 15px;
}
/* 确认按钮small样式 */
.keyui-btn-small {
  padding: 9px 15px;
  font-size: 12px;
  border-radius: 3px;
}
/* 下框按钮区域居中,来一些边距样式 */
.dialog-bottom{
  padding:5px;
  background-color: #fff;
  text-align: center;
}

四、模拟调用场景index.html文件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>弹窗组件封装</title>
    <!-- 引入css样式 -->
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <!-- 弹窗按钮,用于调用点击事件的弹窗 -->
    <button id="btn">弹窗组件</button>

    <!-- 指定content内容,在这里采用id,并默认将其设置为隐藏 -->
    <div id="content" style="display:none;">我是一个小天才</div>
  </body>
</html>
<!-- 引入jquery,因为我们js中的很多调用方法都是基于jquery的所以我们需要在index.js的上方就要引入jquery -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
<!-- 引入我们的keyui组件库 -->
<script src="./index.js"></script>

<script>
  $('#btn').click(function () {
    // 配置参数  index对应我们返还的节点
    var index = keyui.dialog({
      title:'弹窗',// title左上角标题
      content: '#content',// content 指定对应内容指向哪一个标签
      btn: ['确认', '取消'],// 下bottom按钮
      area:['200px','200px'],// 弹窗宽高大小
      yes: function () { //点击确认按钮事件
        console.log(index) //对应上方的index变量,传递给close参数,用于关闭弹窗
        keyui.close(index) //关闭弹窗
      },
      no:function(){ //点击取消按钮事件
        keyui.close(index) //关闭弹窗
      }
    })
  })
</script>

五、dialog弹窗js组件


// 点击删除方法
function rightclose(box) {
  $('#'+box).remove()
}
// dom节点转换为字符串方法
function toInnerHTML(obj){
  // 创建一个节点
  const div = document.createElement("div")
  // 将节点插入进去
  div.appendChild(obj);
  // 将传递进来的dom设置为显示  因为是复制的上方节点嘛
  obj.style.display="block"
  // 获取当当前的dom节点字符串
  var a=div.innerHTML;
  // return出去
  return a;
}
var yes1= function(){
}
var no1 = function(){
}
var keyui = {
  // 弹窗方法  外部可直接使用keyui.dialog调用
  dialog: function (obj) {
    // 设置默认值等等
    var {title='弹窗',content='',btn=[],yes,no,area=['50%','50%']} = obj
    // 创建一个时间戳当层级id
    var date = new Date().getTime()
    // 判断是不是真的传递了yes或者no 如果传递了yes或者no才会让对应的方法赋予上方的全局方法,供与回调
    if(typeof yes === "function"){
      yes1 = yes
    }
    if(typeof no === "function"){
      no1 = no
    }
    // 判断当前有没有btn这个数组
    var dialog_bottom=''
    //有btn并且btn的长度不为0那么说明传递了按钮
    if(btn&&btn.length){
      // 拼接
      dialog_bottom+= `<div class="dialog-bottom">`
      // 循环传递进来的数组
    btn.forEach((element,index) => {
      // 我们在这里只考虑传递两个按钮第一个相当于确认,第二个相当于取消,同时挂载点击方法,也就对应了我们上方的yes1,no1
      dialog_bottom +=  `<div class="keyui-btn keyui-btn-mini ${index==0?'keyui-btn-primary':''}" οnclick="${index==0?'yes1()':'no1()'}">${element}</div>`
     });
     dialog_bottom+= `</div>`
    }
    // 拼接一个dom节点,其实原理上我们还是使用的插入节点的方式。
    var box = $(`<div id="keyui-${date}" class="keyui-dialog-box">
                <div class="keyui-masking-layer">
                  <div class="keyui-dialog" style="width:${area[0]};height:${area[1]}">
                    <div class="keyui-dialog-head">
                    <span>${title}</span>
                      <a href="javascript:;" class="keyui-rightUp-close" οnclick="rightclose('keyui-${date}')">X</a>
                    </div>
                    <div class="keyui-dialog-content">
                      ${content?toInnerHTML($(content).clone(true)[0]):''}
                    </div>
                      ${dialog_bottom}
                  </div>
                </div>
              </div>`)
    // 分别说一下上方对应变量的意思
    /**
     * @param date 时间戳,主要是为了弹窗之中在弹弹窗,用于区分当前究竟是哪一个弹窗
     * @param area[] 0:宽度,1高度
     * @param title 标题
     * @param toInnerHTML($(content).clone(true)[0]) 完全克隆一个dom节点并作为参数传递给toInnerHTML用于拿到dom字符串
     * @param dialog_bottom bottom内容,如果传递的按钮是空的,那么就不会渲染,如果不是就会渲染
     */

    //  将数据插入到对应的body页面中  当然层级我们肯定要设置很高,防止被其他内容盖住
    $('body').append(box)

    // 返回我们拼接的id值  用于关闭这个弹窗
    return $('#keyui-'+date)[0]
  },
  // 关闭弹窗方法,index其实对应的是一个dom节点也就是上方弹窗返还的节点
  close: function (index) {
    //  取当前节点  直接清除
    index.remove();
  }
}

最终效果

在这里插入图片描述

组件的本质:一种人为约定的边界协议 组件是现代前端开发中最基础也最易被误解的核心概念,它并非语法糖或文件格式,而是一种封装了输入契约、输出契约与内部边界的工程化协议。其设计原理根植于关注点分离与单向数据流思想,技术价值体现在可维护性提升、团队协作提效及长期架构演进能力增强。典型应用场景包括UI复用(如Button、DataTable)、逻辑解耦(容器组件+展示组件)以及跨框架共享(@component生态)。理解组件即契约,是写出健壮、可复用、易测试代码的前提。 阅读详情

相关推荐

原生div弹窗实现:无障碍、焦点锁定与CSS动效实战

模态弹窗是Web前端最基础的交互组件之一,其核心在于语义化结构、键盘可访问性与视觉动效的协同。基于WAI-ARIA标准构建的原生div弹窗,无需框架依赖,通过role='dialog'、aria-modal、焦点陷阱(Focus Trap)和transform+opacity动画,确保屏幕阅读器可读、键盘用户可操作、移动端可触达。它解决了ESC失效、背景滚动、焦点逃逸、z-index冲突等高频工程问题,特别适用于政企内网、遗留系统改造及轻量级项目集成。本文聚焦‘手写可控弹窗’的落地细节,覆盖HTML语义、C

weixin_32147929的博客 287

【JavaScript】8.弹出框(Dialog)

最近做项目,用到了弹出框提示信息,就做了个demo,记录总结了一下,对一般的网站来说,弹出框是比较常见的。或是给出用户操作提示,或是通过弹出框打开一个小窗口以提示信息,或是给出错误警示等等。但是由于浏览器自带的弹出窗口alert,confirm,prompt样式比较单调,且不同的浏览器有不同的默认样式设置,所以在日常工作中,给网站做一个自定义的弹出框非常必要。 html部分 Click Me!

返璞归真 2万+

原生js Dialog对话框插件制作19种对话框弹出层拖动

原生js Dialog对话框插件制作19种对话框弹出层拖动

JavaScript 练手小技巧:HTML5 的 dialog 标签制作对话框

对话框,在应用中常常用来做(如,登录、删除信息等)。

九天翔龙的技术博客 1万+

openEuler系统下安装Google Chrome浏览器全攻略(附依赖问题解决方案)

本文详细介绍了在openEuler系统上安装Google Chrome浏览器的完整指南,包括环境准备、多种安装方式、依赖问题解决方案及性能优化技巧。针对openEuler特有的软件生态和依赖管理机制,提供了实用的命令和配置方法,帮助用户克服安装过程中的常见障碍,实现流畅的Chrome使用体验。

hadoop5ranger的博客 1152

流媒体协议-RTMP简介

与rtsp 不同,RTSP(Real-Time Streaming Protocol)是一个控制协议,负责控制媒体流的传输,但不传输媒体数据本身。RTSP 可以通过 TCP 或 UDP 传输 RTP 包来传输音视频数据。 RTMP(Real-Time Messaging Protocol)是一个综合性的协议,不仅可以传输音视频数据,还可以传输信令控制指令。RTMP 使用 TCP 作为传输协议,可以直接在 TCP 连接上传输音视频数据,也可以传输控制指令,实现了音视频流的实时传输和控制

xiaoshuaijinniu的博客 4553

纯js弹窗Dialog组件

纯js弹窗Dialog组件 文章目录纯js弹窗Dialog组件1. js部分2. css样式3. 简单使用4. 效果展示 1. js部分 /* eslint-disable */ const { isTmplValid, createDom, getDom, createSingleDom, cssFromObj, addNode, isDOM } = require('./Common') /** * 根据模板床建 * @param title */ function

weixin_45946494的博客 4550

UE5 Decal混合进阶:如何用DBuffer实现自定义Normal插值(附完整材质配置流程)

本文深入解析了UE5中利用DBuffer技术实现Decal自定义Normal插值的完整流程。通过详细的材质配置步骤和核心算法说明,帮助开发者突破传统混合模式限制,掌握高级法线控制技巧,特别适合需要精细环境细节的3A级项目开发。

table的专栏 225

dialog - JS弹出窗口

请先调用dialog JS var diag = new Dialog();//窗体大小diag.Width = 300;diag.Height = 150; //窗体IDdiag.Title = "内容页为隐藏的元素的html"; //需要显示的内容窗体IDdiag.InvokeElementId="forlogin" //是否显示确认按钮diag.OKEvent = function(...

weixin_34208283的博客 1429

【Matlab/Unity】跨平台UDP通信实战:从数据发送到实时可视化

本文详细介绍了Matlab与Unity之间通过UDP协议实现跨平台通信的实战方法,涵盖数据发送、接收和实时可视化全流程。针对科研仿真和工业设计场景,提供优化代码示例和性能对比数据,帮助开发者解决低延迟传输、线程安全等关键问题,显著提升跨平台协作效率。

weixin_29044713的博客 153

Zemax操作41--公差分析(一)

zemax公差

lzy750750的博客 5973

任务59:从零开始封装一款DIALOG插件

任务59:从零开始封装一款DIALOG插件 1.导语:上节课带着大家封装了一款Z-tree树形菜单这样一个插件,而在封装这个插件的过程中,没有过多参数的配置,也没有过多功能的规划,只是把功能简单实现了,这个过程中,让大家初步了解插件封装的特点,插件封装基本上都是基于面向对象的。基于面向对象的好处在于创建每一个当前类的实例的话,都是一个独立的实例,实例的话就有自己的私有属性,还能调用一些共用的方法能实现我们私有和共用相结合的方式,这种方式对我们来说特别好,在过程中我们还可以把这个信息挂载到实例的私有属性上,这

donglize521521的博客 503

腾讯文档API逆向分析:不用Selenium也能批量导出的黑科技

本文揭秘了如何通过Python逆向分析腾讯文档的隐藏API,实现无需Selenium即可批量导出在线表格的高效方法。详细解析了API调用流程、Cookie维护及异常处理技巧,相比传统方案性能提升显著,适用于大量文档导出的自动化场景。

h9j8k7l6m5n的博客 1202

基于localStorage的纯前端物业管理系统设计与实现

在Web开发中,数据持久化是构建管理系统的核心环节。localStorage作为浏览器内置的本地存储方案,无需服务器即可实现数据读写,为轻量化应用提供了零部署的解决思路。从数据存储原理出发,利用纯HTML、CSS与JavaScript,通过封装统一的Store工具、数据驱动渲染和事件委托,即可实现房产管理、业主登记、费用收缴与报修流转等典型CRUD功能。这种方案适合单机演示、课程设计及小型物业点管理场景,在几百至几千条数据量级下性能表现优异。掌握本地存储与前端数据管理思路,不仅能够快速搭建可用的管理工具,也

weixin_34341229的博客 397

5分钟搞定!用FunASR在本地快速部署达摩院Paraformer语音识别模型

本文提供了一份快速部署指南,教你如何在5分钟内利用FunASR工具包在本地电脑上启动达摩院Paraformer语音识别模型。Paraformer作为一款非自回归端到端模型,以其推理速度快、识别精度高的特点,结合FunASR的一键式模型加载和统一API,让开发者能轻松构建本地语音识别系统,极大降低了前沿AI技术的应用门槛。

q9w8e7r6t5的博客 605

YOLOv12改进策略【独家融合改进】| MobileNetV4+BiFPN,轻松实现降参涨点,适用专栏内所有的骨干替换

可扩展的高效物体检测BiFPN(加权双向特征金字塔网络)

Limiiiing的博客 980

零JS弹窗实现指南:原生HTML/CSS搞定80%交互

弹窗是前端开发中最高频的交互组件之一,传统实现依赖JavaScript操作DOM状态,既引入依赖又增加维护成本。实际上,浏览器本身就是一台完整的状态机,通过popover属性、checkbox hack、:target伪类和details元素等原生能力,可以实现无需JS的弹窗交互,覆盖确认框、下拉菜单、气泡卡片、图片预览等80%以上的日常场景。这些方案不仅代码量少、健壮性强,还天然支持键盘操作与无障碍语义,并在老项目中表现出色。文章从状态机原理出发,详细拆解四种原生弹窗方案的工作原理、选型矩阵与真实踩坑经验

weixin_34032792的博客 296

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

超强Element UI组件库:60+组件一站式解决方案

你还在为Vue.js项目寻找高效、美观的UI组件库吗?还在为组件兼容性、文档质量和社区支持发愁吗?本文将带你全面了解Element UI——这个拥有60+高质量组件的Vue.js 2.0 UI工具包,让你轻松实现企业级应用界面开发,提升开发效率高达40%。读完本文,你将掌握Element UI的安装配置、核心组件使用、主题定制等关键技能,快速上手并应用到实际项目中。 Element UI是由饿了

gitblog_01186的博客 902

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

微信小程序 vant-weapp 弹窗按钮状态同步与样式还原实战

在微信小程序开发中,UI 组件库的状态管理与样式一致性是保障交互体验的基础。vant-weapp 作为主流小程序 UI 库,其 Dialog 组件的 confirm-button 默认不响应 loading、disabled 等状态变化,导致按钮文字切换后圆角丢失、背景色异常、高度抖动等问题。这本质是 slot 插槽机制下组件生命周期与数据驱动视图脱节所致。通过将按钮改造为受控组件,利用 data 驱动 buttonState 三态(idle/loading/done),结合 round 属性、内联样式优先

weixin_34288121的博客 227

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

学习前端开发处方

在真正前端开发中遇到的一些问题,特此总结,以便后期加强学习 一.修复窗口不能一开始在左上角问题 问题描述:目标是希望弹框出现时直接在左上角,不遮挡下面的一些东西,修改前存在的问题:窗口会先出现在屏幕中间,然后再移动到左上角,该弹框采用了fluentUI库中的Dialog,弹框出现默认位置就是中间,先前采用的方案,某个依赖项改变时去设置一个定时器,拿到类名对应的document元素,将其位置设置为左上角(0,0),移动到(100, 100)位置 自己犯的错误:开始就自己去实现一个对话框,然后去关联相关逻

如风逝去 361

漫谈Vue组件库开发

2017年是Vue.js大爆发的一年,React迎来了一个强有力的竞争对手,王者地位受到挑战(撰写此文时github上Vue与React的star数量已逼近)。我们团队这一年有十多个大型项目采用了Vue技术栈,在开发效率、页面性能、可维护性等方面都有不错的收效。 我们希望把这些项目中可复用的功能组件提取出来,给后续项目使用,以减少重复开发,提高效率,同时也为了致敬前端界“出一个框架,造一遍轮子”的

开涛的博客 2140

wp-calypso 中的 ConfirmModal 确认对话框组件:Props API、源码实现与使用指南

ConfirmModal 是 wp-calypso(WordPress.com 的 JavaScript 与 API 前端)中一个轻量、可复用的确认对话框组件,基于 `@wordpress/components` 的 `Modal` 与 `Button` 封装,用于在危险操作、数据变更或关键决策前向用户展示一段确认文案与"取消 / 确认"按钮组。本文以 [client/components/con

gitblog_00075的博客 351

DevUI中后台实战:从组件选型到业务封装与性能优化

企业级管理系统、数据中台与B端SaaS产品的开发中,组件库选型直接决定研发效率与维护成本。成熟的组件库不仅提供统一的交互规范与设计令牌,更通过可定制主题、国际化方案和按需加载能力为工程落地提供支撑。在真实业务场景下,开发者需要掌握表单联动、表格查询链路、弹窗反馈等高频模块的构建方法,并基于基础组件进行适度的二次封装,从而沉淀出贴合业务语义的团队资产。同时,通过覆盖CSS变量实现品牌色切换、合理配置动态引入以控制打包体积,是保障系统长期可维护性的关键实践。本文围绕DevUI展开,梳理组件库选型逻辑、页面落地技

weixin_42514540的博客 116

NC65自定义弹窗参照全链路实现与避坑指南

在用友NC65客开中,‘弹窗参照’并非简单UI组件,而是贯穿界面层、服务总线、数据契约的系统级能力。其核心原理基于UAP框架的MVC+SOA架构,依赖服务注册、PageQuery分页、refCode字段映射等机制实现数据闭环。技术价值在于复用NC65原生权限、缓存与事务体系,避免重复造轮子;典型应用场景包括采购订单供应商选择、客户档案多条件筛选等业务表单增强。实践中需严守XML元数据配置、IRefService接口实现、MyBatis分页规范三大关键约束,尤其注意serviceId一致性与refCode大小

weixin_34095889的博客 276

九个原生浏览器API,替代JS库实现前端性能优化与代码瘦身

现代浏览器在标准化进程中不断沉淀系统级能力,HTML已不止于渲染静态标签,而是内置了大量可直接调用的原生接口。掌握浏览器原生API,不仅有助于前端性能优化,也是实现代码瘦身的关键路径。本文从通用技术概念出发,介绍弹窗、折叠面板、懒加载、动画编排、视图转场等场景下,原生能力如何取代传统JS库:通过内置的焦点管理、异步观察、顶层渲染与合成器线程动画,大幅减少第三方依赖体积,降低主线程阻塞,同时提升可维护性。这些API适用于后台管理系统、移动端H5、中后台复杂交互等多类工程场景,尤其在性能敏感、依赖管控严格的现代

weixin_31509753的博客 248
上一篇: 前端代码连续点击多次按钮,导致数据提交多次,导致后端幂等,解决方案(全局 每次前端请求设置Loading加载效果,请求完成后,关闭Loading加载)
下一篇: vue引入图片报错?VueCli 关于静态资源(图片) 引入问题
归来巨星
归来巨星 新星创作者: 前端开发技术领域 新星创作者: 前端开发技术领域
博客等级 码龄7年 5391粉丝 95原创
评论 37
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

归来巨星

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

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

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

打赏作者

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

抵扣说明:

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

余额充值