Vue八股文笔记自用1

使用 Object.defineProperty() 来进行数据劫持有什么缺点?
在对对象添加属性或者通过下标方式修改数组时,Object.defineproperty无法监测到,Vue底层对数组的监测是通过建立一个对象,在这个对象里重写push,pop,shift,unshift,sort,reverse,splice七种方法,在这七种方法里对数组元素添加响应,并让这个对象指向array.prototype。
在Vue3中已经采用proxy方法,可以监听到所有属性,但由于是ES6的语法,有兼容性问题。
MVVM和MVC
MVC模式分离了Model,View和Controller层,其中View负责页面的显示逻辑,Model层负责存储页面的数据以及进行对数据的操作,View与Model层应用了观察者模式,当Model层发生变化会通知View层更新页面。Controller层是View层与Model层的纽带,当用户与页面进行交互,Controller层中的事件触发器开始工作,通过调用Model层,完成对Model的修改,然后Model层再通知view层更新。
在这里插入图片描述
MVVM模式分为Model,View和ViewModel层:
Model代表数据模型,数据和业务逻辑都在Model层定义
View层代表视图,负责展示数据
ViewModel层监听Model中数据的改变并控制视图的更新,处理用户交互
Model与ViewModel层之间存在着双向数据绑定,因此虽然Model与View层无直接关联,但通过ViewModel层,Model层的数据变化会引起View层视图刷新,View层用户交互改变的数据也会在Model层同步。
在这里插入图片描述
整理语言版
Vue中的MVVM模式包括model层数据层,view层视图层和viewModel层,viewModel层与view层、model层实现了双向数据绑定。ViewModel层做了两件事,一是通过DataBindings完成了Model到View层的映射,无需手动update view,二是通过DOM listeners完成view到Model的监听,这样model就会随view触发事件而改变。
computed 和 watch 的区别

功能上:computed是计算属性,watch是监听一个值的变化,然后执行相应的回调。
是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化时都会执行回调。
是否调用return:computed中的函数必须要用return返回,watch不用
computed默认第一次加载时就开始监听,而watch默认第一次加载不进行监听,如果需要,要加immediate:true
使用场景:computed—当一个属性收到多个属性影响时,如计算购物车商品总价。watch----当一条数据影响到多条数据时,如搜索框。

computed 和 methods 的区别
可以将同一函数定义为methods或者一个计算属性,于结果而言两者相同,不过对于逻辑较为繁杂的一般使用Methods
不同点:computed会基于他的依赖进行缓存,只有当它的依赖发生变化时,computed才会重新求值,否则会从缓存中调用函数。而methods调用时会始终执行该函数。
slot插槽
slot分为三类,默认插槽、具名插槽和作用域插槽。插槽slot是子组件的一个模板标签元素,这一标签是否显示、如何显示由父组件指定。

默认插槽:又名匿名插槽,当slot没有指定name属性时就为默认插槽,一个组件内只能有一个默认插槽(多个默认插槽无法分辨是哪个)
具名插槽,具有name属性的插槽,一个组件内可以有多个具名插槽。
作用域插槽,可以是默认插槽,也可以是具名插槽。作用域插槽的特点是子组件在渲染作用域插槽时,可以将子组件内部的数据传递给父组件,父组件就可以在模板内接收数组并决定如何渲染这个插槽
在Vue2.6.0中,具名插槽和作用域插槽的写法统一为v-slot,缩写为#

{{ user.lastName }} //current-user组件

//父组件

{{ user.firstName }}

父组件是无法获取到user的,于是使用作用域插槽


{{ user.lastName }}

//父组件用v-slot绑定,我们选择将包含所有插槽 prop 的对象命名为 slotProps


{{ slotProps.user.firstName }}

实现原理:当子组件vm实例化时,获取到父组件传入的slot标签内的内容,存放在vm.slot中,默认插槽为vm.slot中,默认插槽为vm.slot中,默认插槽为vm.slot.default,具名插槽为vm.slot.xxx,当组件执行渲染函数时,遇到slot标签,使用slot.xxx,当组件执行渲染函数时,遇到slot标签,使用slot.xxx,当组件执行渲染函数时,遇到slot标签,使用slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。
过滤器的作用,如何实现过滤器
Vue中filters不会修改数据,而是会过滤数据,改变用户看到的输出。
使用场景:

需要格式化数据的情况,比如需要处理时间、价格等数据格式的输出 / 显示。
比如后端返回一个 年月日的日期字符串,前端需要展示为 多少天前 的数据格式,此时就可以用fliters过滤器来处理数据。

过滤器是一个函数,它会把表达式中的值始终当作函数的第一个参数。过滤器用在插值表达式 {{ }} 和 v-bind 表达式 中,然后放在操作符“ | ”后面进行指示。
例如,在显示金额,给商品价格添加单位:

  • 商品价格:{{item.price | filterPrice}}
  • filters: {
    filterPrice (price) {
    return price ? (‘¥’ + price) : ‘–’
    }
    }

    如何保存页面当前的状态
    用keep-alive标签,当组件在keep-alive内被切换时组件的activated,deactivated这两个生命周期钩子函数会被执行,被包裹在keep-alive标签中的组件的状态会被保留



    // 等同于
    <input
    v-bind:value=“message”
    v-on:input=“message=$event.target.value”

    // e v e n t 指代当前触发的事件对象 ; / / event 指代当前触发的事件对象; // event指代当前触发的事件对象;//event.target 指代当前触发的事件对象的dom;
    //$event.target.value 就是当前dom的value值;
    //在@input方法中,value => sth;
    //在:value中,sth => value;

    v-if v-show v-html原理

    v-if:v-if会调用addIfCondition方法,生成vnode的时候会忽略对应节点,所以不会被渲染。
    v-show:v-show会生成vnode,也会生成真实dom插入dom树中,但会被修改display属性。
    v-html:v-html就是将innerHTML设置为v-html的值。
    v-pre:不进行解析

    为什么不建议v-if v-for连用

    v-for优先级高于v-if,每次都会进行v-if的判断
    v-if是局部编译卸载,与v-for配合使用性能消耗大。

    常见的事件修饰符及其应用

    .stop: 等同于event.stopProppagation(),防止事件冒泡
    .prevent 等同于event.preventDefault(),阻止浏览器默认行为
    .capture 与事件冒泡方向相反,事件捕获由外到内
    .self 只触发自己范围内元素,不包含子元素
    .once 只触发一次
    事件冒泡的应用在于给父元素添加事件,从而在子元素触发事件时通过事件冒泡调用到父元素身上的事件。

    v-if v-show 区别

    手段:v-if是动态的往DOM树内插入删除dom节点,v-show是控制dom元素的display样式来控制显隐。
    编译过程:v-if切换有一个局部编译、卸载的过程。
    编译条件:v-if是惰性的,如果初始条件为假,那么什么都不做,只有在条件第一次变为真时才开始局部编译;而v-show无论首次条件是否为真都会被编译,然后被缓存,而且dom元素保留

    v-model是如何实现的,语法糖实际是什么

    作用在表单元素上,动态绑定input的value指向message变量,并且在触发input事件时动态的将message设置为目标值。

    // 等同于 //$event 指代当前触发的事件对象; //$event.target 指代当前触发的事件对象的dom; //$event.target.value 就是当前dom的value值; //在@input方法中,value => sth; //在:value中,sth => value;

    作用在组件上 在自定义组件中,v-model会默认利用名为value的prop和名为input的事件
    本质是用prop和$emit实现

    Vue.component(‘base-checkbox’, {
    model: {
    prop: ‘checked’,
    event: ‘change’
    },
    props: {
    checked: Boolean
    },
    template: `
    <input
    type=“checkbox”
    v-bind:checked=“checked”
    v-on:change=“$emit(‘change’, $event.target.checked)”

    `
    })


    这两个组件具体交互是怎么样的呢:
    首先将父组件转化为如下格式


    父组件将lovingVue变量传入base-checkbox组件,如果不使用model选项使用的prop名为value(默认),一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用来避免这样的冲突:
    Vue.component(‘base-checkbox’, {
    model: {
    prop: ‘checked’,
    event: ‘change’
    },
    props: {
    checked: Boolean
    },
    template: <input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change', $event.target.checked)" >
    })

    base-checkbox子组件接收props,将其动态绑定到input的checked上,并向父组件传出名为change的事件,父组件将接收到的值赋值给lovingVue
    总结来讲,v-model作用在组件上时,默认prop时value,event是input,model选项可以修改这个默认。

    data为什么是一个函数而不是对象
    Javascript中的对象是引用数据类型,当多个实例引用一个对象时,只要一个实例对这个对象进行操作,其他实例中的数据也会发生变化。
    而在Vue中,我们编写组件需要让每个组件的数据独立,即组件的复用性,我们需要让同一个组件在不同地方引用时有私有的数据空间,所以要写成函数返回值的模式。
    对keepalive的理解

    keepalive组件能够缓存子组件,使其不经历销毁流程(即beforeDestroy, Destroyed),而是经历(activated, deactivate)。
    keepalive有三个配置项,分别是include,exclude和max,分别是缓存名单,不缓存名单和最大缓存个数。配合路由的meta进行使用。
    keepalive在各个生命周期内做的事:created—初始化一个cache和keys,前者用来存放缓存的虚拟节点集合,后者用来缓存组件的key集合; mounted — 检测include和exclude变化进行相应操作; destroyed:清除所有缓存相关的东西
    keepalive自身组件不会渲染到页面上。

    $nextTick原理及作用
    Vue中DOM更新是异步的,只要观察到数据变化,Vue将开启一个队列,并缓冲同一个事件循环中发生的所有数据改变并去重,然后在下一次事件循环中,Vue刷新队列并执行工作。
    在Vue中,DOM的更新一般是在一轮事件循环中的最后执行,但当我们执行一个同步操作(如获取DOM)时,同步任务栈并未完成,异步任务队列也就没有被放进执行栈,这时我们就可以使用nextTick进行更改。nextTick进行更改。
    nextTick进行更改。nextTick当中的回调函数会被放在下一次事件循环中执行,这样就保证了这个回调一定是在Dom更新完成之后执行的
    使用场景:

    当数据变化后执行的某个操作,而这个操作需要使用随数据变化而变化的DOM结构时,这个操作的方法要在nextTick中。

    {{ message }}

    getMyWidth() {
    this.showMe = true;
    //this.message = this. r e f s . m y W i d t h . o f f s e t W i d t h ; / / 报错 T y p e E r r o r : t h i s . refs.myWidth.offsetWidth; //报错 TypeError: this. refs.myWidth.offsetWidth;//报错TypeError:this.refs.myWidth is undefined
    this.KaTeX parse error: Expected '}', got 'EOF' at end of input: …message = this.refs.myWidth.offsetWidth;
    })
    }

    在vue生命周期中,如何要在created钩子里获取dom,需要放在nextTick里,watch同理。
    立即更改某个数据后,获取DOM元素发现其数据并没有更改,此时是因为更新DOM的操作被放在了一个异步队列中,直到同一事件循环中所有数据变化完成,才会进行异步队列的处理。所以这本质上是一种优化策略。$nexttick返回的是一个Promise对象。

    Vue中给data中的对象属性添加一个新属性会发生什么,如何解决

    • {{value}}

    addObjB方法给obj添加了一个b属性,值为obj.b,这个添加显然是会生效的,但视图却不会刷新,因为在vue实例创建时,obj.b并未声明,因此就没有被Vue转换为响应式属性,也就不会触发视图的更新,这时就需要用KaTeX parse error: Expected '}', got 'EOF' at end of input: …jB(){ this.set(this.obj,“b”,“obj.b”)

    Vue2响应式原理对于数组的处理
    Vue2响应式原理的核心就是Object.defineProperty,而对于数组而言,如果把它当作对象,key为下标,value为元素来监听的话,在splice、reverse等方法就会多次触发getter和setter,这在数据量大时的性能消耗是巨大的。
    于是Vue2重写了数组的七种方法,建立了一个对象,这个对象指向Array.prototype,首先这个对象可以通过原型链调用原始方法更改数组,其次这个对象会在调用这些方法的同时提示watcher更新,并对push unshift splice这些新增元素的方法进行判断,即对新增的元素进行响应式的处理。

    单页面与多页面对比
    概念:
    SPA单页面应用(SinglePage Web Application),指只有一个主页面的应用,一开始只需要加载一次js、css等相关资源。所有内容都包含在主页面,对每一个功能模块组件化。单页应用跳转,就是切换相关组件,仅仅刷新局部资源。
    MPA多页面应用 (MultiPage Application),指有多个独立页面的应用,每个页面必须重复加载js、css等相关资源。多页应用跳转,需要整页资源刷新。
    在这里插入图片描述
    Vue data 中某一个属性值发生变化,视图会立即同步执行渲染吗
    不会,因为Vue对DOM的更新是异步的,Vue会维护一个队列,然后监听到数据变化就将同一事件循环的这些数据进行缓冲,同时,如果同一个watcher被重复触发即数据被多次更改,只有最后一次更改会被推入缓冲队列中,然后在下一个事件循环tick中,Vue刷新队列并执行工作。
    mixin extends 留坑
    留坑
    Vue自定义指令
    除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。
    一般使用自定义指令只用来操作DOM展示,不修改内部的值。下面举一个输入框的例子,当页面加载时,该元素将获得焦点 (注意:autofocus 在移动版 Safari 上不工作)。事实上,只要你在打开这个页面后还没点击过任何内容,这个输入框就应当还是处于聚焦状态。现在让我们用指令来实现这个功能:
    // 注册一个全局自定义指令 v-focus
    Vue.directive(‘focus’, {
    // 当被绑定的元素插入到 DOM 中时……
    inserted: function (el) {
    // 聚焦元素
    el.focus()
    }
    })

    当然也可以局部注册
    directives: {
    focus: {
    // 指令的定义
    inserted: function (el) {
    el.focus()
    }
    }
    }
    然后你可以在模板中任何元素上使用新的 v-focus property,如下:

    子组件可以直接改变父组件的数据吗
    不可以,因为Vue提倡单向数据流。每次父组件更新时,子组件的所有prop都会刷新为最新的值。只能通过$emit派发一个自定义事件,父组件收到后由父组件更改
    assets和static的区别
    相同点:assets和static两个都是存放静态资源文件。项目中所需要的资源图片文件,图标等都可以放在这两个文件夹下。
    不同点:assets中存放的静态资源文件会经过打包上传,而static不会进行打包。
    Vue项目的性能优化
    (1) 编码

    减少data中的数据,data中的数据都是响应式的,也就意味着data中的数据都会增加getter和setter,会收集对应的watcher
    v-if和v-for不连用。v-if的条件变化会导致整个v-for内的dom插入删除。
    采用keep-alive缓存组件
    路由懒加载,异步加载组件
    防抖、节流
    按需引入第三方模块
    长列表滚动到可使界面动态加载
    图片懒加载
    (2) 打包
    生产环境下删除console.log,用uglifyjs-webpack-plugin
    使用CDN加载第三方模块留坑why
    thread-load多线程打包
    splitChunks抽离公共文件 ?留坑

    对SPA的理解
    SPA就是单页面应用,他会web页面初始化的时候加载对应的html,css,js,当页面加载完成,SPA不会因为用户操作而重新加载资源,而是用路由机制实现HTML的变化。
    hash路由
    hash路由的本质是锚点(#)定位,可以总结出以下几个特点

    hash路由会触发网页跳转,即浏览器的前进后退
    hash可以改变url,但不会触发页面的重新加载(hash的改变记录在window.history)中,即不会刷新页面,不会重新加载,自然就不算是http请求。
    锚点后面(#)的内容是不会提交到server端的。

    history路由
    history路由使用了h5提供的pushState(),replaceState方法实现浏览器的前进后退,通过history.state将任意类型的数据添加到记录中。用户在history模式下操作切换页面,虽然url会被改变,但浏览器不会刷新页面也不会往服务器发送请求,但会触发代码里的监听事件从而改变页面内容,所以无需向服务端发送请求。但如果此时用户刷新页面,浏览器发送给服务端的就是新的url,所以服务端要进行配置使得这些url返回同一个index.html
    生命周期
    生命周期
    Vue实例有一个完整的生命周期,从开始创建,初始化数据,编译模板,挂载DOM到渲染,然后更新DOM,渲染,卸载等一系列流程。

    beforeCreate: 数据观测和初始化事件还未开始,此时还未对data进行响应式化,watcher也就没有依赖数据,所以在这个data、computed等都不可访问。
    created: 实例创建完成,但DOM树未挂载,无法获取DOM元素,但data、methods、computed等都已经配置完成。
    beforeMount:在挂载前执行,实例已经完成编译模板,把data中的数据和模板生成html。此时还没有挂载html到页面上,render函数首次被调用生成虚拟dom。
    mounted:挂载完成,此时虚拟dom已经被转化为真实dom并插入到DOM树上。
    beforeUpdate:数据有更新时被调用
    updated:已经用diff算法用最小dom开支完成重新渲染dom
    beforeDestroy:实例销毁之前调用,此时实例仍然可用
    destroyed:实例销毁后调用,所有事件监听器会被移除,子实例也被销毁
    另外keep-alive也有独特的生命周期,为activated和deactivated,用keep-alive包裹的组件在切换时不会销毁,而是缓存到内存中并执行deactivated钩子函数,命中缓存渲染后会执行activated钩子函数

    生命周期详细版

    首先我们把创建Vue实例到created这部分称为初始化阶段
    判断是根组件还是子组件,如果是根组件就合并全局配置到vm.options上,如果是子组件就把深层次的配置对象挂载到vm.options上,如果是子组件就把深层次的配置对象挂载到vm.options上,如果是子组件就把深层次的配置对象挂载到vm.options上
    初始化实例属性,如$children, $refs,初始化事件监听、渲染函数等。
    调用beforeCreate
    初始化data, methods, computed, watch等
    调用created函数
    进入模板编译阶段

    模板编译阶段在created和beforeMount之间
    模板解析:将模板字符串通过正则转化为抽象语法书AST
    优化:遍历AST,将其中的静态节点打上标记
    将AST转换为渲染函数
    进入挂载阶段

    挂载阶段在beforeMount 和 Mounted间

    调用beforeMount钩子
    生成虚拟DOM,进行数据劫持,依赖收集。
    将虚拟DOM渲染为真实DOM挂载到页面
    调用Mounted函数

    销毁阶段

    beforeDestroy
    移除依赖,销毁子组件
    销毁组件

    Vue子组件和父组件执行顺序
    父组件 beforeCreate
    父组件 created
    父组件 beforeMount
    子组件 beforeCreate created beforeMount mounted
    父组件 mounted
    父组件 beforeUpdate
    子组件 beforeUpdate updated
    父组件 updated

    在哪个生命周期发送ajax请求
    在created发送异步请求,因为在created发送异步请求能更快获取到服务端数据,减少页面加载时间。个人理解时beforeMount要生成虚拟dom,而且beforeMount之后要将虚拟dom转为真实dom插入到dom树上,所以排除beforeMount;而mounted要在子组件挂载完之后才能调用,所以排除mounted,而且mounted发送异步请求,由于此时DOM已经挂载,可能会造成抖动。
    组件通信
    props/ e m i t 父组件向子组件传值用 p r o p s , 子组件向父组件传值用 emit 父组件向子组件传值用props,子组件向父组件传值用 emit父组件向子组件传值用props,子组件向父组件传值用emit绑定事件

    // 父组件

    //子组件

    全局事件总线(emit/emit/emit/on)
    eventbus事件总线适合父子兄弟组件间通信,相当于将传输的数据存储在事件总线中,其他组件通过引入事件总线进行传输。
    // event-bus.js

    import Vue from ‘vue’
    export const EventBus = new Vue()

    求和: {{count}}

    依赖注入(provide/ inject)
    适用于祖孙组件通信,即多层次的父子组件通信,无需多层props
    provide/ inject是vue提供的两个钩子,与data,methods同级

    provide用来发送数据或方法
    inject 用来接收数据或方法

    provide() {
    return {
    num: this.num
    };
    }

    provide() {
    return {
    app: this
    };
    }
    data() {
    return {
    num: 1
    };
    }

    inject: [‘app’]
    console.log(this.app.num)
    复制代码
    也可以这样写,来访问父组件的所有属性
    provide() {
    return {
    app: this
    };
    }
    data() {
    return {
    num: 1
    };
    }

    inject: [‘app’]
    console.log(this.app.num)

    ref/$refs
    这个用在子组件上就可以访问子组件的实例


    $ p a r e n t parent parentchildren

    使用 p a r e n t 可以让组件访问父组件的实例(访问的是上一级父组件的属性和方法)使用 parent可以让组件访问父组件的实例(访问的是上一级父组件的属性和方法) 使用 parent可以让组件访问父组件的实例(访问的是上一级父组件的属性和方法)使用children可以让组件访问子组件的实例,但是,$children并不能保证顺序,并且访问的数据也不是响应式的。

    .sync v-model
    两者作用相同,都是父子组件v-bind $emit的语法糖,.sync默认子组件emit的事件名为update:传递数据名,v-model默认子组件是接受value的prop,emit的是input,不过可以通过model属性配置。
    vuex
    $root
    获取app.vue的数据
    slot
    作用域插槽
    $attrs, l i s t e n e r s 绑定在子组件的非 p r o p 属性会作为子组件根元素的 c s s 属性,可以通过 i n h e r i t A t t r s = f a l s e 阻止这种继承,同时通过 listeners 绑定在子组件的非prop属性会作为子组件根元素的css属性,可以通过inheritAttrs=false阻止这种继承,同时通过 listeners绑定在子组件的非prop属性会作为子组件根元素的css属性,可以通过inheritAttrs=false阻止这种继承,同时通过attrs接收这些属性。它也可以绑定v-bind:" a t t r s " 在孙子组件上,孙子组件上就可以通过 p r o p s 接收。组件通信总结父子组件父组件 v − b i n d 动态绑定数据给子组件传输,子组件用 p r o p s 接收;子组件用 t h i s . attrs"在孙子组件上,孙子组件上就可以通过props接收。 组件通信总结 父子组件 父组件v-bind动态绑定数据给子组件传输,子组件用props接收;子组件用this. attrs"在孙子组件上,孙子组件上就可以通过props接收。组件通信总结父子组件父组件vbind动态绑定数据给子组件传输,子组件用props接收;子组件用this.emit传递事件名和参数,父组件用v-on绑定事件接收
    深层次的可以用provide,inject, 祖先组件用provide,写法类似data,子孙组件用inject,写法类似props
    p a r e n t 和 parent和 parent c h i l d r e n 父组件用 children 父组件用 children父组件用refs访问子组件实例

    兄弟组件
    eventbus,本质相当于创建了一个空的vue实例,其他组件引入这个实例,在这个实例上传递和监听事件。
    为什么动态绑定的图片地址需要用require
    因为不使用require,地址不会进行编译。首先我们知道,如果使用静态指定图片地址,进行编译后,图片指定的地址会被改变。
    // vue文件中静态的引入一张图片

    logo

    //最终编译的结果
    //这张图片是可以被正确打开的
    logo

    为什么data要是函数
    当组件实例化时,如果data是对象,那么所有组件的实例就会指向同一个对象,那么一个实例数据的更改就会污染其他实例。data如果是函数,那么每次组件实例化都会调用这个函数返回新的对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

JackieChan_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值