vue-big


01、v-if和v-show指令

定义

v-if指令是通过销毁和重建DOM来使元素显示或隐藏。
v-show指令是通过修改元素的display属性让其显示或隐藏。


应用场景

v-if适用于不需要频繁切换条件的场景。
v-show适用于需要频繁切换条件的场景。


Vue的生命周期

生命周期描述
beforeCreate(创建前)组件实例被创建之初,组件的属性生效之前。
created(创建后)组件实例已经完全创建,属性也绑定,但真实DOM还没有生成,$el还不可用。
beforeMount(载入前)在挂载开始之前被调用,相关的render函数首次被调用。
mounted(载入后)el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。
beforeUpdate(更新前)组件数据更新之前调用,发生在虚拟DOM打补丁之前。
update(更新后)组件数据更新之后。
beforeDestory(销毁前)实例销毁前调用,实例仍然可用。
destoryed(销毁后)实例销毁之后调用,Vue实例指示的所有东西都会解绑,所有事件监听器和所有子实例都会被移除。

02、Vue路由拦截


03、Vue中父子组件生命周期钩子函数的执行顺序

渲染顺序

1、先父后子,完成顺序:先子后父
2、父beforeCreate => 父created => 父beforeMount => 子beforeCreate => 子created => 子beforeMount => 子mounted => 父mounted


更新顺序

1、父更新导致子更新,子更新完成后父更新完成
2、父beforeUpdate => 子beforeUpdate => 子updated => 父updated


销毁顺序

1、先父后子,完成顺序:先子后父
2、父beforeDestroy => 子beforeDestroy => 子destroyed => 父destroyed


04、MVVM

MVVMModel-View-ViewModel的缩写,也就是把MVC中的controller演变成ViewModel
1、Model表示数据模型层。
2、View表示视图层,也就是UI组件。
3、ViewModelViewModel层的桥梁,数据绑定到viewModel层并自动渲染到页面中,视图变化会通知viewModel层更新数据。


05、v-for和v-if

v-for的优先级高于v-if,连用的话每个循环出来的元素都添加了v-if,会造成性能问题,影响渲染速度。


06、Vue中的data

同一个组件被复用多次会创建多个实例,在JavaScript中,对象是引用关系。如果data是一个对象的话,这些实例用的是同一个构造函数。为了保证组件的数据独立,要求每个组件都必须通过data函数返回一个对象作为组件的状态。


07、v-model(双向绑定)

1、使用数据劫持和发布订阅模式结合的方式实现,也就是说数据和视图同步,数据发生变化,视图跟着变化,视图发生变化,数据也随之发生变化。
2、核心就是使用Object.defineProperty()方法来实现。
3、v-model本质上是语法糖,v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件。
3.1、texttextarea元素标签使用value属性和input事件。
3.2、checkboxradio使用checked属性和change事件。
3.3、select字段将value作为prop并将change作为事件。


08、route和router的区别

1、$route是路由信息对象,包括pathparamshashqueryfullPathmatchedname等路由信息参数。
2、$router是路由实例对象,包括了路由的跳转方法和钩子函数等。


09、vue-router

概念

vue-router3种路由模式,分别是hashhistoryabstract
1、hash:使用URL hash值来作路由。支持所有浏览器,包括不支持HTML5 History Api的浏览器。
2、history:依赖HTML5 History Api和服务器配置实现。
3、abstract:支持所有JavaScript运行环境,如Node.js服务器端。如果发现没有浏览器的Api,路由会自动强制进入abstract模式。


源码

switch (mode) {
	case 'history':
		this.history = new HTML5History(this, options.base);
		break;
	case 'hash':
		this.history = new HashHistory(this, options.base, this.fallback);
		break;
	case 'abstract':
		this.history = new AbstractHistory(this, options.base);
		break;
	default:
		if (process.env.NODE_ENV !== 'production') {
			assert(false, `invalid mode: ${mode}`);
		}
};

相关链接
1、掘金-原文


10、computed(计算属性)和watch(监听)的区别及应用场景

定义

1、computed计算属性是用来声明式的描述一个值依赖了其它的值。当模板里的数据绑定到一个计算属性上时,Vue会在其依赖的值发生改变时更新DOM
2、watch监听的是定义的变量,当定义的变量值发生变化时,调用对应的回调方法。


应用场景

1、当需要进行数值计算,并且依赖于其它数据时,应该使用computed,因为可以利用computed的缓存特性,避免每次获取值时,都要重新计算。
2、当需要在数据变化时执行异步或开销较大的操作时,应该使用watch,因为watch允许执行异步操作,限制了执行该操作的频率,并在得到最终结果前,可以设置中间状态。这些都是计算属性无法做到的。


11、Proxy与Object.defineProperty优势对比

Proxy的优势

1、Proxy可以直接监听对象而非属性。
2、Proxy可以直接监听数组的变化。
3、Proxy有多达13种拦截方法,不限于applyownKeysdeletePropertyhash等等是Object.defineProperty不具备的。
4、Proxy返回的是一个新对象,可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改。
5、Proxy作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利。


Object.defineProperty的优势

兼容性好,支持IE9,而Proxy存在浏览器兼容性问题,而且无法用polyfill磨平,因此Vue的作者才声明需要等到下个大版本3.0或以上才能用Proxy重写。


相关链接
1、掘金-原文


12、VueX

定义

VueX是一个专为Vue.js应用程序开发的状态管理模式和库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。


模块

1、state:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
2、getter:允许组件从store中获取数据,mapGetters辅助函数仅仅是将store中的getter映射到局部计算属性。
3、mutation:是唯一更改store中状态的方法,且必须是同步函数。
4、action:用于提交mutation,而不是直接变更状态,可以包含任意异步操作。
5、module:允许将单一的store拆分为多个store且同时保存在单一的状态树中。


13、Vue中的$nextTick

异步方法,异步渲染最后一步,与JavaScript事件循环联系紧密。主要使用了宏任务微任务定义了一个异步方法,多次调用$nextTickt会将方法存入队列,通过异步方法清空当前队列。


14、Vue组件间通信

父子组件通信

在父组件标签上使用冒号声明自定义属性,给自定义属性赋值。在子组件中使用props接收父组件传过来的值即可。


子父组件通信

1. 在父组件标签上使用@自定义函数,并给自定义函数绑定一个函数名。在子组件中使用$emit触发父组件中的函数即可。
2. 在父组件标签上使用ref给组件重新取个新名字,并且在需要获取子组件值的地方使用this.$refs新名字value即可。


兄弟组件通信

1. eventBus方法通过一个空的Vue实例作为中央事件总线,也就是事件中心,用它来触发事件和监听事件,从而实现各组件间的通信。
2. VueX是一个专为Vue.js应用程序开发的状态管理模式和库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。


15、Vue路由传参数

1、在query对象中定义属性和值,在需要的地方使用this.$route.query接收即可。
2、在params对象中定义属性和值,在需要的地方使用this.$route.params接收即可。
注意query传参需要使用pathname来引入。params传参需要使用name来引入。


16、delete和Vue.delete删除数组的区别

1、delete只是被删除的元素变成了empty/undefined, 其他的元素的键值还是不变。
2、Vue.delete直接删除数组, 改变数组的键值。


17、Vue插槽

定义

slot通俗的理解就是占位,在组件模板中占好了位置,当使用该组件标签时,组件标签里面的内容就会自动填充到该位置,也就是替换组件模板中slot的位置。


内容插槽

1、插槽内可以包含普通文本。
2、插槽内可以包含任何模板代码,包括HTML
3、插槽内可以添加其他组件。
5、插槽内可以使用data中的数据。
规则
1、父模板里的所有内容都在父级作用域中编译。
2、子模板里的所有内容都在子级作用域中编译。


后备内容,也就是默认内容插槽

有时候需要给插槽设置一个具体的默认内容,当别的组件没有给内容的时候,默认的内容就会被渲染。


具名插槽

当一个组件里面需要多个插槽的时候,slot标签元素有一个特殊的特性,那就是name属性。slot元素的这个特性可以用来定义额外的插槽。
实现
1、在父组件中的子组件标签里面使用template标签来实现,并且在template标签上绑定v-slot:value
2、在子组件的slot标签上使用name等于父组件中v-slot冒号后面的值即可。


作用于插槽

插槽里面的数据不是直接写死在标签上,而是在data函数中获取。
实现
1、在父组件的子组件标签里面使用双花括号绑定语法即可。
2、在子组件的slot标签里面使用双花括号绑定语法即可。


相关链接
1、掘金-原文
2、源码实现


18、Vue响应数据的原理

定义

Vue在初始化数据时,会使用Object.defineProperty重新定义data中的所有属性,Object.defineProperty可以使数据的获取与设置增加一个拦截的功能,拦截属性的获取,进行依赖收集。拦截属性的更新操作,进行通知。


具体的过程

首先Vue使用initData初始化用户传入的参数,然后使用new Observer对数据进行观测,如果数据是一个对象类型就会调用this.walk操作对象,内部使用defineeReactive循环对象属性定义响应式变化,核心就是使用Object.defineProperty重新定义数据。


19、DOM

19.1、在什么阶段才能访问操作DOM

在钩子函数mounted被调用前,Vue已经将编译好的模板挂载到页面上,所以在mounted中可以访问操作DOM
注意mounted不会承诺所有的子组件也都一起被挂载。如果希望等到整个视图都渲染完毕,可以用vm.$nextTick替换掉mounted


mounted: function () {
  this.$nextTick(function () {
    // Code that will run only after the
    // entire view has been rendered
  })
}

19.2、虚拟DOM的优缺点
19.2.1、优点

1、保证性能下限:框架的虚拟DOM需要适配任何上层API可能产生的操作,它的一些DOM操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的DOM操作性能要好很多,因此框架的虚拟DOM至少可以保证在不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限。
2、无需手动操作DOM:程序员不再需要手动去操作DOM,只需要写好ViewModel的代码逻辑即可,框架会根据虚拟DOM和数据双向绑定原理来实现视图的更新,极大的提高开发效率。
3、跨平台:虚拟DOM本质上是JavaScript对象,而DOM与平台强相关,相比之下虚拟DOM可以进行更方便地跨平台操作,例如服务器渲染、weex开发等等。


19.2.2、缺点

无法进行极致优化:虽然虚拟DOM做了合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟DOM无法进行针对性的极致优化。


19.3、虚拟DOM实现原理

1、使用JavaScript对象模拟真实DOM树,对真实DOM进行抽象。
2、使用diff算法比较两棵虚拟DOM树的差异。
3、使用pach算法将两个虚拟DOM对象的差异应用到真正的DOM树上。


19.4、如何从真实DOM到虚拟DOM

1、将模板转换成AST树,AST用对象来描述真实的JavaScript语法,也就是将真实DOM转换成虚拟DOM
2、优化树。
3、将AST树生成代码。


19.5、用VNode来描述一个DOM结构

虚拟节点就是用一个对象来描述一个真实的DOM元素。首先将template,真实DOM先转成ASTAST树通过codegen生成render函数,render函数里的_c方法将它转为虚拟DOM


19.6、虚拟DOM

1、由于DOM操作耗时长,且DOM对象的体积大,单个divDOM属性就有294个之多。
2、Virtual DOM就是用一个原生的JavaScript对象去描述一个DOM节点,所以它比创建一个DOM的代价要小很多。
3、VNode是对真实DOM的一种抽象描述,它的核心定义无非就几个关键属性,标签名、数据、子节点、键值等,其它属性都是用来扩展VNode的灵活性以及实现一些特殊feature的。由于VNode只是用来映射到真实DOM的渲染,不需要包含操作DOM的方法,因此它是非常轻量和简单的。
4、Virtual DOM到真实的DOM需要经过以下过程:VNodecreatediffpatch


20、diff

一个树的完全diff算法是一个时间复杂度为O(n*3),vue进行优化转化成O(n)
1、最小量更新, key很重要。这个可以是这个节点的唯一标识,告诉diff算法,在更改前后它们是同一个DOM节点。
2、v-for为什么要有key,没有key会暴力复用,举例子的话随便说一个比如移动节点或者增加节点(修改DOM),加key只会移动对应节点,减少了DOM操作。
3、只有是同一个虚拟节点才会进行精细化比较,否则就是暴力删除旧的,插入新的节点。
4、只进行同层比较,不会进行跨层比较。


diff算法的优化策略:四种命中查找,四个指针
1、旧前与新前(先比开头,后插入和删除节点的这种情况)
2、旧后与新后(比结尾,前插入或删除的情况)
3、旧前与新后(头与尾比,此种发生了,涉及移动节点,那么新前指向的节点,移动到旧后之后)
4、旧后与新前(尾与头比,此种发生了,涉及移动节点,那么新前指向的节点,移动到旧前之前)


21、SPA单页面应用

21.1、说说你对SPA单页面的理解,它的优缺点分别是什么
理解

SPA(single page application)仅在Web页面初始化时加载相应的HTMLJavaScriptCSS。一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现HTML内容的变换,UI与用户的交互,避免页面的重新加载。


优点

1、用户体验好且快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染。
2、基于上面一点,SPA相对服务器压力小。
3、前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理。


缺点

1、初次加载耗时多:为实现单页Web应用功能及显示效果,需要在加载页面的时候将JavaScriptCSS统一加载,部分页面按需加载。
2、前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理。
3、SEO难度较大:由于所有的内容都在一个页面中动态替换显示,所以在SEO上有其天然的弱势。


21.2、如何优化SPA应用的首屏加载速度慢的问题

1、将公用的JavaScript库通过script标签外部引入,减小app.bundle的大小,让浏览器并行下载资源文件,提高下载速度。
2、在配置路由时,页面和组件使用懒加载的方式引入,进一步缩小app.bundle的体积,在调用某个组件时再加载对应的js文件。
3、加一个首屏loading图,提升用户体验。


21.3、Vue的SPA如何优化加载速度

1、减少入口文件体积。
2、静态资源本地缓存。
3、开启Gzip压缩。
4、使用SSRnuxt.js


22、v-on

v-on可以监听多个方法吗

可以。

<input type="text" :value="name" @input="onInput" @focus="onFocus" @blur="onBlur" />

v-on常用修饰符

1、stop该修饰符将阻止事件向上冒泡。同理于调用event.stopPropagation()方法。
2、prevent该修饰符会阻止当前事件的默认行为。同理于调用event.preventDefault()方法。
3、self该指令指当事件是从事件绑定的元素本身触发时才触发回调。
4、once该修饰符表示绑定的事件只会被触发一次。


23、Vue中的ref

ref被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的$refs对象上。如果在普通的DOM元素上使用,引用指向的就是DOM元素;如果用在子组件上,引用就指向组件实例。


24、Vue模板编译

Vue模板渲染的原理

Vue中的模板template无法被浏览器解析并渲染,因为这不属于浏览器的标准,不是正确的HTML语法,所以需要将template转化成一个JavaScript函数,这样浏览器就可以执行这一个函数并渲染出对应的HTML元素,就可以让视图跑起来了,这一个转化的过程,就成为模板编译。
模板编译又分三个阶段,分别是解析parse 、优化optimize和生成generate,最终生成可执行函数render
1、parse阶段:使用大量的正则表达式对template字符串进行解析,将标签、指令、属性等转化为抽象语法树AST
2、optimize阶段:遍历AST,找到其中的一些静态节点并进行标记,方便在页面重新渲染的时候进行diff比较,在进行diff比较时直接跳过这些静态节点,优化runtime的性能。
3、generate阶段:将最终的AST转化为render函数字符串。


Vue template模板的预编译

1、对于Vue组件来说,模板编译只会在组件实例化的时候编译一次,生成渲染函数之后再也不会进行编译。因此,编译对组件的runtime是一种性能损耗。
2、模板编译的目的仅仅是将template转化为render函数,这个过程,正好可以在项目构建的过程中完成,这样可以让实际组件在runtime时直接跳过模板渲染,进而提升性能,这个在项目构建的编译template的过程,就是预编译。


25、Vue动态绑定class与style

25.1、class
对象语法

<div v-bind:class="{ active: isActive }"></div>

数组语法

<div v-bind:class="[activeClass, errorClass]"></div>

25.2、style
对象语法

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

数组语法

<div v-bind:style="[baseStyles, overridingStyles]"></div>

官网链接
1、官网-原文


26、可以在哪个生命周期内调用异步请求

可以在createdbeforeMountmounted钩子函数中调用异步请求,因为在这三个钩子函数中,data已经创建,可以将服务端返回的数据进行赋值。推荐在created钩子函数中调用异步请求,因为在created钩子函数中调用异步请求能更快获取到服务端数据,减少页面loading时间;且ssr不支持beforeMountmounted钩子函数,所以在created中调用异步请求有助于一致性。


27、Vue的介绍

Vue是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue也完全能够为复杂的单页应用提供驱动。


28、keep-alive

概念

keep-aliveVue的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁。


作用

组件在切换过程中将状态保留到内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性。


原理

created函数调用时将需要缓存的VNode节点保存在this.cache中;在render执行时,如果VNodename符合缓存条件,则会从this.cache中取出之前缓存的VNode实例进行渲染。


原文链接
1、CSDN-vue中keep-alive的使用及详解
2、CSDN-Vue中keep-alive的使用详解


29、让CSS只在当前组件中起作用

将当前组件的<style>修改为<style scoped>即可。


30、Vue的两个核心

数据驱动和组件系统。


31、Vue中的key

Vuev-for正在更新已渲染过的元素列表时,它默认执行就地复用策略。如果数据项的顺序被改变,Vue不是移动DOM元素来匹配数据项的改变,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,就需要为每项提供一个唯一key属性。key属性的类型只能为string或者number类型。


key的特殊属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes。如果不使用keyVue会使用一种最大限度减少动态元素并且尽可能的尝试修复,且再利用相同类型元素的算法。使用key,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。


32、Vue性能优化

Web技术优化

1、开启Gzip压缩
2、浏览器缓存
3、CDN的使用
4、使用Chrome Performance查找性能瓶颈


编码优化

1、事件代理和事件销毁
2、路由懒加载和图片资源懒加载
3、第三方插件的按需引入
4、防抖和节流
5、v-ifv-show区分使用场景
6、computedwatch区分使用场景
7、v-for遍历必须为item添加key,且避免同时使用v-if
8、长列表性能优化
9、<keep-alive></keep-alive>


Webpack优化

1、使用Webpack对图片进行压缩
2、减少ES6转为ES5的冗余代码
3、提取公共代码
4、模板预编译
5、提取组件的CSS
6、构建结果输出分析
7、Vue项目的编译优化


33、Vue的vm.$set的实现原理

1、如果目标是数组,直接使用数组的splice方法触发响应式。
2、如果目标是对象,会先判读属性是否存在、对象是否是响应式,最终如果要对属性进行响应式处理,则是通过调用defineReactive方法进行响应式处理。defineReactive方法就是Vue在初始化对象时,给对象属性采用Object.defineProperty动态添加gettersetter功能所调用的方法。


34、Vue初始化做了什么

rollup配置文件中找到编译的入口,在入口文件中主要做了两件事情。
1、重写了$mount方法增加新的功能,首先判断有没有render函数如果没有,将template编译成render函数;如果有调用mount渲染到DOM上。
2、注册Vue静态方法complierHTML字符串编译成render


35、Vue单向数据流

所有的prop都使得其父子prop之间形成了一个单向下行绑定,父级prop的更新会向下流动到子组件中,但是反过来则不行。这样是防止从子组件意外改变父级组件的状态,从而导致应用的数据流向难以理解。除此之外,每次父级组件发生更新时,子组件中所有的prop都会刷新为最新的值。这意味着不应该在一个子组件内部改变prop。如果这样做了,Vue会在浏览器的控制台中发出警告。子组件想修改时,只能通过$emit派发一个自定义事件,父组件接收到后,由父组件修改。


36、Vue如何兼容IE

使用babel-polyfill插件。


34、Vue自定义指令


35、Vue的生命周期

生命周期描述
beforeCreate: 创建前组件实例被创建之初,组件的属性生效之前。
created: 创建后组件实例已经完全创建,属性也绑定,但真实DOM还没有生成,$el还不可用。
beforeMount: 载入前在挂载开始之前被调用,相关的render函数首次被调用。
mounted: 载入后el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。
beforeUpdate: 更新前组件数据更新之前调用,发生在虚拟DOM打补丁之前。
update: 更新后组件数据更新之后。
beforeDestory: 销毁前实例销毁前调用,实例仍然可用。
destoryed: 销毁后实例销毁之后调用,Vue实例指示的所有东西都会解绑,所有事件监听器和所有子实例都会被移除。

36、Vue3.0


-----------------------------ZF-----------------------------


1、渐进式框架

类库或者框架都是重量级的,里面包含很多方法,但是实际项目开发中,我们用不到这么多东西,所以在开发他们的时候,会把功能按照模块进行单独开发,使用者可根据自身情况选择一个模块导入使用。
渐进式框架


2、MVVM

MVVM


3、new Vue

new Vue


4、常用指令

常用指令


5、for in 和 for of

for in
for of


6、过滤器/计算属性/监听器

计算属性/过滤器/监听器


7、过滤器(filters)

第一次过滤
第二次过滤


8、计算属性(computed)

计算属性
文字详解


9、监听器(watch)

监听器
监听器


10、class 和 style


11、Vue 的生命周期


12、Vue 的 ref

ref


12、Vue 的组件components

组件命名规则


13、components 的插槽(slot)


14、父组件给子组件传参

父组件给子组件传值


15、单项数据流

单项数据流


16、组件间传值


17、组件间传值之 ref

组件间传参之 ref


18、VueX

vueX


19、v-model

deletev-model


是否可枚举是否可枚举


是否允许当前属性被修改是否允许当前属性被修改


get/setget/set


this.$set(this.obj,‘sname’,‘你好’)
this.$set(this.obj,'name','你好')


对象处理方式对象处理方式


数组处理方法数组处理方法


数据渲染数据渲染


视图数据更改的监听视图数据更改的监听

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值