《Vue》初识、摘要及入门

按键修饰符

和事件修饰符同理,v-on能绑定的不仅仅是click这种点击事件,还包括了对键盘上的键盘进行监听,键盘修饰符则是为键盘事件被触发是增加的一些修饰

注意

另外修饰符是可以连续使用的,比如:

上面的keyup事件必须是alt和c键同时松开时才会触发clear函数

条件渲染

v-if

v-if指令用户条件性的将绑定DOM渲染出来,比如

//只有当awesome的值为true的时候,h1标签才会被渲染

//如果awesome的值为false,那么这个h1将不会被渲染进DOM树

Vue is awesome!

于js相似,既然有了if,那么必定有else-if和else,所以对应的指令为v-else-if和****v-else

A
B
C
Not A/B/C

上例中的v-if例子就是一个最完整的v-if条件渲染,如果type的值是A,那么就会渲染A这个div,之后的B,C,Not A/B/C这个3个div将不会被渲染,会被vue忽略掉,type的值是B,C或其他则是同理,这4个div只会根据条件渲染其中的一个,剩下的3个将不会被渲染进DOM树

v-show

使用方式和v-if一致,后面的值是一个布尔值,区别在于v-show如果是false那么就相当于在css中将display属性设置成none,虽然在页面上不可见,但是实际上是存在DOM树里面的,如果值是true则会显示在页面上

//如果ok的值是true,那么h1标签会被显示,否则则会隐藏

Hello!

v-if和v-show

一般来说,v-if 有更高的切换开销,而v-show有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好

列表渲染

列表渲染,也就是指令v-for,该指令基于一个数组或对象来渲染一个列表,具体例子如下:

假设现在有一个长度为100的数组,数组中的每一项都是一个对象,对象上有一个属性message,其值是一个string类型,现在我们在ul中生成100个li,每个li中的文字对应message的值

使用v-for的写法如下

    • {{ item.message }}

      • items:是我们要遍历的目标数组;

      • item:循环时的数组中的每一个对象;

      • index:当前遍历对象的索引;

      • item.message:是对象上的属性值;

      注意:这边:key是vue为了更好的进行内部排序而绑定的标志,绑定的值的要求是必须本次循环中是唯一的,不能有重复,不然如果一旦li的顺序有所变动,vue在内部就不知道哪个对应哪个

      如果遍历的目标是一个对象,那么例子如下:

      • {{ name }}: {{ value }}

        new Vue({

        el: ‘#v-for-object’,

        data: {

        object: {

        title: ‘How to do lists in Vue’,

        author: ‘Jane Doe’,

        publishedAt: ‘2016-04-10’

        }

        }

        })

        结果:

        • title:How to do lists in Vue’

        • author:Jane Doe

        • publishedAt:2016-04-10

        遍历对象时,上例中有两个参数,第一个属性也就是value对应对象的值,第二属性name对应对象的键值;

        当然,如果遍历对象时,还有第三个参数index,其值是当前遍历对象的索引

        v-model

        双向数据绑定,可以用 v-model 指令在表单 、 及 等元素上创建双向数据绑定。绑定后,如果元素上手动输入会直接影响data中的值,而data中的值发生变化,那么元素上的显示也会发生变化

        比如:

        Message is: {{ message }}

        new Vue({

        el: ‘#v-for-object’,

        data: {

        message:‘’

        }

        })

        现在给input绑定了一个v-model指令,其值是在data中定义的message变量,此时,如果我们在input中输入:你好,那么在data中的message属性的值将同步被更新为“你好”,只会因为p元素中也绑定了message,所以p元素中的message位置也将同步修改为“你好”;

        如果,这时有一个按钮,按钮的作用是将触发一个函数,函数会将message的值清空,点击按钮后,message的值被清空了,这是input输入框中的值将会被清空,p元素message的位置也会被清空;

        v-model本质上是一个语法糖,在Vue中是通过给dom元素同时绑定v-bind:value和v-on:input事件达到最终的效果的;它在内部对不同的表单组件做了识别,针对不同的表单组件实现不同的方案;

        示例:现在自定义了一个输入框组件,其内部包含了一个input和一个label,在其他组件引用后,在组件上绑定了v-model,那么在组件内部的input如何接收v-model上的内容呢?

        //自定义组件使用

        //组件内部

        <input @input=“ e m i t ( ′ i n p u t ′ , emit('input', emit(input,event.target.value)” :value=“value”>

        **

        input和和textarea

        在这两个元素上v-model的用法差不多,就是和上面的那个例子一样,其绑定后,在元素内的输入会同步修改data中的属性值,而data中的属性值一旦发生便会,也会同步修改元素中输入框内的值,这是一个双向的影响

        复选框

        单个复选框,绑定到布尔值:

        那么选中时,值为true,未选中时,值为false;

        多个复选框,绑定到同一个数组:


        Checked names: {{ checkedNames }}

        new Vue({

        el: ‘#example-3’,

        data: {

        checkedNames: []

        }

        })

        那么,选中的复选框的value值将被加入数组,未选中时其value值将被从数组移除;

        单选按钮



        Picked: {{ picked }}

        new Vue({

        el: ‘#example-4’,

        data: {

        picked: ‘’

        }

        })

        v-model将会把选中的单选框的value值赋值给picked,换句话说picked的值就是当前被选中的单选框的value值

        选择框

        单选时和单选按钮相似,其绑定的变量的值就是当前选择框选中的value值;多选时绑定到一个数组和复选框相似,其数组内的值就是当前全部被选中的项的value值

        计算属性


        首先明确一点,计算属性是一个属性,而不是方法,因此调用的时候不能有括号,在vue中存在一个函数,叫做computed,也叫做计算属性,这个属性专门用于复杂逻辑的处理,比如,从服务器上获取了一堆属性值,这堆值没办法直接使用,需要通过一系列的处理才能使用(具体例子如:请求得到的数据中用户的名字,联系方式,地址,邮箱都是不同的键值对,而在html里需要合并成一个完整的字符串显示),那么就可以在计算属性中处理完了,在放入html中

        另外,当计算属性中的某个值发生变化时,计算属性的结果将重新计算,并且页面将被重新渲染,比如现在定一个一个计算属性name,而这个name中有两个值:姓和名,一旦其中某一个发生了变化,那么计算属性name将会被重新执行,然后所有使用到name的地方也将被连带这重新执行渲染

        注意:如果某个计算属性在页面中没有被使用到,那么此时计算属性的变更并不会引起页面的渲染

        var vm = new Vue({

        el: ‘#example’,

        data: {

        message: ‘Hello’

        },

        computed: {

        // 计算属性的 getter

        reversedMessage: function () {

        // this 指向 vm 实例

        return this.message.split(‘’).reverse().join(‘’)

        }

        }

        })

        console.log(vm.reversedMessage) // => ‘olleH’

        vm.message = ‘Goodbye’

        console.log(vm.reversedMessage) // => ‘eybdooG’

        例子中,reversedMessage的值依赖于message,那么当message的值发生变化时,计算属性reversedMessage将会重新计算执行;

        注意

        计算属性是有缓存的,也就是说,如果其中的值并没有发生变化,那么即使多次被访问,其值并不会重新运行计算,它会将之前计算好的结果给返回出去,只有在其值发生变化的时候,才会重新运行计算结果;

        因此注意,下例这个值是不会更新的,其值就是首次创建时返回的值

        computed: {

        now: function () {

        return Date.now()

        }

        }

        侦听属性


        侦听属性,watch,该属性用于监测某些属性,比如需要监测某个值是否发生了变化,因为一旦某个值发生了变化,那么带来的结果就会有一系列的响应,侦听属性的函数名,就是属性名,其函数体内的方法就是一旦侦听的属性发生了变化,那么函数体内的代码就会执行;

        ar vm = new Vue({

        el: ‘#demo’,

        data: {

        firstName: ‘Foo’,

        lastName: ‘Bar’,

        fullName: ‘Foo Bar’

        },

        watch: {

        //这里的firstName,就是data中的firstyName,代表侦听的属性就是firstyName

        firstName: function (val) {

        this.fullName = val + ’ ’ + this.lastName

        },

        //这里的lastName,就是data中的lastName,代表侦听的属性就是lastName

        lastName: function (val) {

        this.fullName = this.firstName + ’ ’ + val

        }

        }

        })

        这里,watch中里设定了监听了data中的两个属性:firstName和lastName,一旦data中的fistName或者lastName的值发生变化,那么对应在watch中的对应的方法就会被执行;

        到这里,是不是觉得计算属性computed和侦听属性watch有点像,区别在于:

        • 计算属性是:其函数体内的某个属性的值发生变化,那么计算属性就会重新执行,有点多对一的意思;

        • 侦听属性是:监测的属性一旦发生变化会随之改变其他的属性,有点一对多的意思;

        另外侦听属性很容易被滥用,比如上例,其实可以用计算属性重写

        var vm = new Vue({

        el: ‘#demo’,

        data: {

        firstName: ‘Foo’,

        lastName: ‘Bar’

        },

        computed: {

        fullName: function () {

        return this.firstName + ’ ’ + this.lastName

        }

        }

        })

        生命周期


        每个Vue实例在被创建的过程中都会经过一系列的初始化过程,在这些过程中Vue会进行数据监听,编译模版,实例挂载到DOM等等一系列操作,在这个过程中,Vue为用户在不同阶段都预留了一个函数接口,这些接口函数会在不同的阶段被执行,这些接口也叫做生命周期钩子函数

        注意:钩子函数可以用es6的写法,也可以用es5的写法但是****唯独不可以用箭头函数,因为生命周期的钩子函数中的this指向的是vue的实例,而箭头函数是没有自己的this的;

        new Vue({

        data: {

        a: 1

        },

        created: function () {

        // this 指向 vm 实例

        console.log('a is: ’ + this.a)

        }

        })

        //最终会打印:a is 1

        图解

        在这里插入图片描述

        beforeCreate()

        该阶段运行在实例创建前的状态 ,**此时的el和data尚未被创建,因此值都是undefined;**这个阶段可以除了整个系统的Loading

        el就是我们挂载的根节点元素,比如下例,创建的vue实例就是挂载在id为app的DOM元素上的,当然也可以将#app改为.app,那么就代表挂载的对象是类名为app的DOM元素;

        var app = new Vue({

        el: ‘#app’,

        data: {

        message: ‘Hello Vue!’

        }

        })

        Created()

        该阶段在实例被创建后就立即调用,此时的data中已经有数据了,并且可以运行方法,使用计算数据和侦听属性之类的了,但是该阶段挂载还没有开始,因此el是undefined;

        通常在这个阶段,通过axios等将数据请求下来,存储至vuex或者data中;

        beforeMount()

        该阶段在实例被挂载开始前调用;不过通常该阶段能做的事在created()中也能做;这个钩子函数其实不常用;

        mounted()

        该阶段在实例挂载后被调用,这是el被创建的(虚拟DOM)替换了,注意的是mounted不会保证所有的自组件也都被一起挂载,如果你希望等到整个视图都渲染完毕,可以在mounted的内部调用vm.$nextTick

        mounted: function () {

        this.$nextTick(function () {

        // Code that will run only after the

        // entire view has been rendered

        })

        }

        在mounted()之前,页面上所有的数据都是通过占位符占位的,而mounnted之后占位符的内容发生更新,数据被填充到页面上;

        beforeUpdate()

        该钩子函数会在页面上数据更新前调用,在这个阶段适合在更新前访问现有的DOM;

        updated()

        该钩子函数会在页面上数据更新之后调用,这个阶段DOM已经更新,适合处理依赖新DOM的操作,然而在绝大多数情况下,根据DOM或者说根据数据需要改变现有状态,通常使用计算属性或者侦听属性比较好

        同样,updated不会保证所所有的子组件页都被一起重绘,如果希望等到所有的视图都重绘完毕,那么可以在updataed里使用vm.$nextTick

        updated: function () {

        this.$nextTick(function () {

        // Code that will run only after the

        // entire view has been re-rendered

        })

        }

        beforeDestroy()

        实例销毁前调用,在这一步,实例仍然完全可用,可以在这个钩子函数内清理事件,计时器或者取消订阅操作等;

        destroyed()

        实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。

        比如现在在该组件上有一个定时器,希望离开组件时定时器被清除,那么就可以在beforeDestroy()或者destroyed()这两个钩子函数中的一个设置清除定时器,因为当执行beforeDestroy()或者destroyed()这个两个钩子函数时,就代表着离开当前组件了;

        组件


        组件是Vue中最为强大的功能之一,它可以将HTML元素进行封装重用,这样整个页面其实就被组件化了,页面上类似的元素部分可以进行剥离,然后组件化,这样既可以减少代码量,也方便对相同的部分进行统一管理,一旦需要修改那么只需要修改一处便可以将多处进行同时修改;

        简单示例

        // 定义一个名为 button-counter 的新组件

        Vue.component(‘button-counter’, {

        data: function () {

        return {

        count: 0

        }

        },

        template: ‘You clicked me {{ count }} times.’

        })

        上例是在Vue实例上添加(也可以说是注册)了一个名为button-counter的组件,注册之后,那么在Vue上的任意地方可以进行任意次数的使用,并且因为data是通过函数返回的形式定义的数据,因此多个组件之间的数据并不相互影响,而且每个组件都有自己的data,computed,watch,methods以及生命周期,具体使用例子如下:

        组件创建

        通过template标签创建,比如

        这是template构建的组件

        注意:所有元素都必须包含在一个元素中,或者说组件的根组件有且只有有个;

        组件注册

        通过上例,相信对组件有了一个简单的了解,组件的注册分为两种:全局注册局部注册

        这两者的区别在于,全局组件一旦注册,那么就可以在根实例下任意一个地方使用,但是这种注册往往是不够理想的,设想下,如果你全局注册了一个组件,在通过像webpack这样的构建系统时,即使你全局注册的组件没有被使用到,webpack仍然会将组件进行打包,这样最终的打包结果代码量就会无意义的增大;

        局部注册则不同,当制作完局部组件之后,那么如果哪个组件需要使用,就通过components进行局部注册,这样组件可以在当前组件中被使用了;

        全局注册

        通过Vue.component()这个方法给全局注册一个组件

        Vue.component(‘my-component-name’, { /* … */ })

        第一个参数是一个字符串,代表注册组件的名字,第二个参数是组件代码;

        全局组件通常只用来注册一些非常常用的基础组件,比如:自定义的按钮,自定义的输入框,自定义的icon等等;

        局部注册

        局部注册则是需要在当前组件中注册

        import ComponentA from ‘./ComponentA.vue’

        export default {

        components: {

        ComponentA

        }

        }

        首先通过import将组件引入,之后在当前的components中注册,这样注册后就可以在当前组件中使用了;

        通过vue-cli搭建的项目,更多的使用的是局部注册的方式引入组件,使用组件;

        注意

        因为HTML对大小写不敏感,因此强烈建议组件的命名遵循W3C的规范,也就是:字母全部小写且必须包含一个连字符

        可以这样注册

        import ComponentA from ‘./ComponentA.vue’

        export default {

        components: {

        ComponentA

        }

        }

        但是使用的适合则写成

        组件通讯

        父组件向子组件传递

        父组件上定义一个属性,子组件通过prop接收属性,具体如下

        父组件示例

        //静态属性

        如果是静态属性,那么直接在组件上写上属性名和属性值,但实际情况除了UI库,很少会有静态属性直接写在组件上,更多是动态值传递给子组件,这个时候就用到了v-bind指令

        //动态属性

        //:name是v-bind:name的缩写

        通过v-bind指令给name绑定了一个变量username

        注意:假如组件上只有绑定了属性,没有绑定属性值,比如下例,只有绑定了name,没有为name绑定任何值,那么在子组件中获得的值默认为boolean类型,且值为true

        子组件示例

        props: {

        // 基础的类型检查 (nullundefined 会通过任何类型验证)

        propA: Number,

        // 多个可能的类型

        propB: [String, Number],

        // 必填的字符串

        propC: {

        type: String,

        required: true

        },

        // 带有默认值的数字

        propD: {

        type: Number,

        default: 100

        },

        // 带有默认值的对象

        propE: {

        type: Object,

        // 对象或数组默认值必须从一个工厂函数获取

        default: function () {

        return { message: ‘hello’ }

        }

        },

        // 自定义验证函数

        propF: {

        validator: function (value) {

        // 这个值必须匹配下列字符串中的一个

        return [‘success’, ‘warning’, ‘danger’].indexOf(value) !== -1

        }

        }

        }

        • type:类型检查,value为对应类型的构造函数,如果是null或者undefined,则会通过任何类型的验证,如果是多种类型则可以通过传入数组[String,Array]

        • required:是否是必填的

        • default:默认值,默认值为对象或者数据的默认值必须从一个工程函数获取;

        • validator:自定义娇艳函数,范围true为通过,false为不通过;

        在子组件中通过一个对象props接收父组件传递过来的属性,该对方的键名就是父组件上的属性名

        值的注意的是,值的传递是单向数据流,也就是说,父组件值的变化会实时更新到子组件的props中,但是子组件的变化不会影响到父组件,这意味着不应该在子组件去修改props中的值,如果在子组件中需要监听props的值,并且当值改变时需要有一系列的操作,那么这是应该使用计算属性等方式重新计算组件,例如下面两种示例

        1.props传递可一个初始值,子组件希望将这个值保存到本地

        props: [‘initialCounter’],

        data: function () {

        return {

        counter: this.initialCounter

        }

        }

        2.props传递了一个原始值,子组件希望通过这个原始值计算出了一个新的值供组件使用

        props: [‘size’],

        computed: {

        normalizedSize: function () {

        return this.size.trim().toLowerCase()

        }

        }

        子组件向父组件传递

        在子组件中,以某些事件为契机,触发后通过**$emit()**方法将消息和数据传递到父组件,在父组件中,通过v-on将事件接收,比如

        子组件

        传递

        methods:{

        updata(){

        this.$emit(‘msg’,data)

        }

        }

        在子组件中有一个点击事件,点击后,出发了$emit(),第一个参数是定义的名字,父组件中通过这个名字接收数据,第二个参数就是需要传递的数据;

        父组件

        methods:{

        getData(msg){

        console.log(msg)

        }

        }

        getData中的形参msg就是子组件传递上来的数据data;

        动态组件

        通过标签动态加载,动态组件可以更大的帮助用户去复用代码,而不是重新构造

        computed:{

        currentComponent(){

        return this.ab?LifeCycleA : FOR;

        }

        }

        通过判断this.ab的值选择当前的的位置是加载组件LifeCycleA还是组件FOR

        另外通过这种方式动态加载组件会重新卸载,加载组件,如果在组件内部有什么修改,切换后修改是不会被保存的,因此,如果需要保存,Vue提供了一种内置的解决办法:,将这个标签包裹component标签,例如

        包裹后,会去缓存当前的组件实例,因此如果当前的组件再一次进入页面,那么Vue将不会去重新创建渲染进页面,而是从缓存中将该页面取出来,插入页面中;

        插槽


        vue上面的原文是:Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 元素作为承载分发内容的出口。

        换句话说,也就是定义的内容会被自动加载替换到slot这个元素中,拿个实际场景为例,很多后台管理页面,注册,登录,密码找回使用的是同一套背景模版,区别在于上面的输入框不同,那么实际上开发的时候背景模版只需要单独封装成一个组件,并且预留一个作为接口,之后分别在登录,注册,密码找回中引入,实际上登录注册密码找回的代码就仅仅是输入部分的编写设计

        例子:

        navigation-link是一个基础组件,标签内部的"Your Profile"将会替换组件内部的标签

        Your Profile

        navigation-link组件内部

        <a

        v-bind:href=“url”

        class=“nav-link”

        同样上例中"Your Profile"部分可以是文字,也可以是HTML代码,如果是HTML代码,HTML代码将整体替换组件内部的部分

        另外标签内部是可以有内容的,它仅仅只会在插槽没有被使用到的时候才会被渲染,成为**“后备内容”**,

        Submit

        如果标签内部没有写入内容,那么button上就会有默认文字"Submit",如果有文字,那么会显示文字内容;

        具名插槽

        如果一个组件内需要有多个插槽,那么就需要给不同的插槽进行命名,这样,指定的内容可以通过指令插入到指定的插槽内,另外如果没有命名实际上vue会给他一个默认添加一个名字default,例如

        //虽然没有添加name,但是实际上vue会给它添加一个name='default’属性,默认插槽有且只有一个

        通过给插槽添加属性name来确定为具名插槽,在向具名插槽提供内容的时候,我们可以在一个 元素上使用 v-slot 指令(缩写#),并以 v-slot 的参数的形式提供其名称:

        //v-sort:header 等同于 #header

        Here might be a page title

        A paragraph for the main content.

        And another one.

        Here's some contact info

        自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

        深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

        因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

        img

        既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

        由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

        如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

        最后

        前端CSS面试题文档,JavaScript面试题文档,Vue面试题文档,大厂面试题文档,需要的读者可以戳这里免费领取!

        如果标签内部没有写入内容,那么button上就会有默认文字"Submit",如果有文字,那么会显示文字内容;

        具名插槽

        如果一个组件内需要有多个插槽,那么就需要给不同的插槽进行命名,这样,指定的内容可以通过指令插入到指定的插槽内,另外如果没有命名实际上vue会给他一个默认添加一个名字default,例如

        //虽然没有添加name,但是实际上vue会给它添加一个name='default’属性,默认插槽有且只有一个

        通过给插槽添加属性name来确定为具名插槽,在向具名插槽提供内容的时候,我们可以在一个 元素上使用 v-slot 指令(缩写#),并以 v-slot 的参数的形式提供其名称:

        //v-sort:header 等同于 #header

        Here might be a page title

        A paragraph for the main content.

        And another one.

        Here's some contact info

        自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

        深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

        因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

        [外链图片转存中…(img-dbwfttEU-1713610171510)]

        [外链图片转存中…(img-ugxmfDrt-1713610171511)]

        既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

        [外链图片转存中…(img-dYwalgWp-1713610171511)]

        由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

        如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

        [外链图片转存中…(img-OpTXVyi6-1713610171511)]

        最后

        前端CSS面试题文档,JavaScript面试题文档,Vue面试题文档,大厂面试题文档,需要的读者可以戳这里免费领取!

        [外链图片转存中…(img-MLAoLlbw-1713610171511)]

        [外链图片转存中…(img-QmULYqlg-1713610171512)]

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

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

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

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

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

      抵扣说明:

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

      余额充值