vue2初学1-37

  • vue是什么

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

  • 特点
    1,采用组件化模式(HTML,CSS JS),提高代码复用率让代码更好维护
    2,声明式编码(命令式编码,一步一个指令,一步也少不了),让编码人员无需直接操作DOM,提高开发效率
    3,使用虚拟DOM+优秀的Diff算法,尽量复用DOM节点
  • 写一个例子
    <!-- 准备一个容器 -->
    <!-- {{}}只是分隔符 -->
    <div id="root">
        <h1>插值语法</h1>
        <h3>你好,{{name}}</h3>
        <h1>指令语法</h1>
        <a v-bind:href="school.url.toUpperCase()" x="hello">点我去{{school.name}}</a>  //v-bind可以简写成:,里面的内容也要js表达式

    </div>
    <script>
        Vue.config.productionTip=false  //阻止启动时产生生产提示
        //创建Vue实例
        new Vue({
            el:'#root' ,  //指定当前Vue实例为root容器服务,这个值通常使用css选择器字符串
            data:{        //存储数据数据供el指定的容器使用
                name:'Vue',
                school:{
                    name:'baidu',
                    url:'http://www.baidu.com'
                }
            }
        })

       
    </script>

el和data的两种写法:
1,el:(1)在new Vue时候配置;(2)先创建vue实例,给实例起名字,再通过实例.$mount(‘#root’)指定el的值
2,data:(1)对象式{};(2),函数式data(){return } 或者 data:function(){ return },但是不要写箭头函数,一旦写了箭头函数,this就不再是Vue的实例。组件必须要用函数式

vue模板语法有2大类:
1,插值语法:功能是用于解析标签体内容,写法{{}},可以直接读取到data中所有属性
2,指令语法:功能是用于解析标签,其中包括标签属性,标签体内容,绑定事件;

tips:
1,容器和实例之间是一对一
2,真实开发中只有一个vue实例,并且只会配合着组件一起使用
3,{{}}中要写JS表达式(JS表达式:一个表达式只会产生一个值,可以放在任何一个需要值的地方,比如a,a+b;JS代码语句:if(){};for(){};),JS表达式可以自动读取到data中的所有属性。
4,data发生改变,页面中用到该数据的地方就会自动更新

  • 数据绑定
    vue有两种数据绑定的方式
    1,单向绑定,数据只能从data流向页面,v-bind简写为:
    2,双向绑定:页面和data互流,但是双向绑定只能应用在表单类元素上(input,select),v-model:value可以简写为v-model,因为本身就是收集value值的
    <div id="root">
        单向数据绑定:<input type="text" :value="name"><br>
        双向数据绑定:<input type="text" v-model="name">
    </div>

    <script>
        new Vue({
            el:'#root',
            data:{
                name:'csdn'
            }
        })
    </script>
  • MVVM模型
    Vue虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例。
    M:model,对应data中的数据
    V:View,模板(DOM 页面)
    VM:ViewModel,Vue实例对象(包括DOM Listeners,Data Bindings)

tips:data中所有属性最后都出现在vm身上;vm身上所有属性以及vue原型上所有属性,在vue模板中可以直接使用

  • 数据代理
    数据代理:通过一个对象代理对另一个对象中属性的操作(读,写。。)
        //obj2读/写obj1中的x
        let obj1={x:100}
        let obj2={y:300}
        Object.defineProperty(obj2,'x'{
            get(){
                return obj1.x
            },
            set(value){
                obj1.x=value
            }
        }

vue中的数据代理是通过vm对象来处理data对象中的属性的操作
好处:更加方便的操作data中的数据
基本原理:通过Object.defineProperty()把data对象中所有属性添加到vm上;为每一个添加到vm上的属性都指定一个getter/setter(set函数);在getter/setter内部操作(读写)data中对应的属性

<div id="root">
        <h2>地址名称:{{name}}</h2>
    </div>

 var vm=new Vue({
            el:'#root',
            data:{
                name:'csdn' //使用Object.defineProperty()使{{name}}和data里的name发生数据代理
            }
        }
  • 事件的处理
    事件的基本使用:
    1,使用v-on:xxx或@xxx绑定事件,其中xxx是事件名
    2,事件的回调需要配置在method对象中,最终会在vm上
    3,method配置的函数不要用箭头函数,否则this会是window;配置的函数都是被vue管理的函数,this指向vm或组件实例对象
    4,@click="demo"和@click=“demo($event)"效果一致,但后者可传参

<div id="root">
    <button @click="show1">点我1</button>
    <button @click="show2($event,32)">点我2</button>
</div>
<script>
    var vm=new Vue({
        el:'#root',
        data:{
            name:'csdn'
        },
        methods:{
            show1(evnet){
                //console.log(event.target.innerText)
                alert(1232245)
            },
            show2(event,number){
                console.log(event,number)
                alert("你好")
            }
        }
    })
</script>
  • 事件修饰符
 <style>
        * {
            margin-top: 20px;
        }
        .demo1{
            height: 55px;
            background-color: aquamarine;

        }
        .box1{
            padding: 5px;
            background-color: blue;
        }
        .box2{
            padding: 5px;
            background-color: rgb(108, 108, 220);
        }
        .list{
            width: 200px;
            height: 20px;
            background-color: pink;
            overflow: auto;
        }
        li{
            height: 100px;
        }
    </style>
</head>
<body>
    <div id="root">
        <h2>welcome {{name}}</h2>
        <!-- 阻止默认事件发生,即a在点击之后不会跳转 -->
        <a href="https://editor.csdn.net" @click.prevent="show">jump</a> 
        <!-- 阻止冒泡 在method中写就是event.stopPropagation -->
        <div class="demo1" @click="show">
            <button @click.stop="show">jump</button> 
        </div>
        <!-- 事件触发一次 -->
        <button @click.once="show">jump</button> 
        <!-- 使用事件的捕获模式 -->
        <div class="box1" @click.capture="showmsg">
            div1
            <div class="box2" @click="showmsg">
                div2
            </div>
        </div>
        <!-- 只有event.target是当前操作的元素时触发事件,某种程度上是阻止冒泡 -->
        <div class="demo1" @click.self="show">
            <button @click="show">jump</button> 
        </div>
        <!-- 事件默认行为立刻执行,无需等待事件回调执行完 -->
            <!-- 鼠标滚轮滚动是wheel 滚动条滚动是scroll -->
        <ul @whell.passive="demo" class="list">
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
        </ul>
    </div>
    <script>
        new Vue({
            el:'#root',
            data:{
                name:CSDN
            },
            methods:{
                show(event){
                    // event.preventDefault()   //取消默认行为
                    // alert("你好")
                    console.log(event.target)
                },
                showmsg(msg){
                    console.log(msg)
                },
                demo(){
                    for(let i=0;i<1000;i++){
                        console.log(1234)
                    }
                    console.log("tired")
                }
            }
        })
    </script>
</body>
  • 键盘事件
    Vue按键的别名:
    回车----enter;删除----delete(捕获删除或退格键);退出----esc;空格----space;上----up;下----down;左----left;右----right;换行—tab(要keydown)
    (Vue没有提供的别名的按键,可以使用按键原始的key值去绑定,但要注意转为kebab-case(两个词中间用短横杠)
    系统修饰符(ctrl,shift,alt,meta):要配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键事件才被触发@keyup.ctrl.y;配合keydown使用:正常触发事件。
    (可以用keycode去指定具体键(不推荐)Vue.config.keyCodes.自定义键名=键码;可以去定制按键别名
   <div id="root">
        <h2>{{name}}</h2>
        <input type="text" placeholder="按下回车输入" @keyup.enter="show">
    </div>

    <script>
        Vue.config.keyCodes.huiche=13//定义了键为回车
        new Vue({
            el:'#root',
            data:{
                name:'csdn'
            },
            method:{
                show(e){
                    console.log(e.key)//按键名
                }
            }
        })
    </script>
  • 计算属性
    定义:要用的属性不存在,要通过已有的属性计算得到
    原理:底层借助了Object.defineproperty方法提供的getter和setter
    getter执行:初次读取会执行一次;当依赖的数据发生改变会被再次调用
    优点:和method相比内部有缓存机制(复用),效率更高,调试方便
    tips:计算属性最终会出现在vm上,直接读取使用即可;如果计算属性被修改,要写setter去响应修改,且set中要引起计算时依赖的数据发生变化
<body>
    <!-- <div id="root">
        姓:<input type="text" v-model="name1"><br>
        名:<input type="text" v-model="name2"> -->
        <!-- 可以用{{name1.slice(0,3)}}-{{name2}}但是不推荐 -->
        <!-- 全名:<span>{{fullName()}}</span>
    </div> -->

    <!-- <script>
        Vue.config.productionTip=false
        new Vue({
            el:'#root',
            data:{
                name1:'cs',
                name2:'DN'
            },
            methods:{
                fullName(){
                    return this.name1+'-'+this.nam2
                }
            }
        })
    </script> -->


    <!-- 简单有用的 -->

    <div id="root">
        姓:<input type="text" v-model="name1"><br>
        名:<input type="text" v-model="name2">
        测试:<input type="text" v-model="x"><br>
        全名:<span>{{全名}}</span><br>
    </div>

    <script>
        Vue.config.productionTip=false
        let a=1
        var vm=new Vue({
            el:'#root',
            data:{
                name1:'cs',
                name2:'DN'
            },
            methods:{
                demo(){

                }
            },
            computed:{
                fullName:{
                    get(){
                        return this.name1+'-'+name2//this是vm
                    },

                    set(value){
                        const arr=value.split('-')
                        this.name1=arr[0]
                        this.name2=arr[1]
                    }
          /* 
                当只考虑读取不考虑修改时将上面fullname简写,
                直接写成函数形式来代替getter,但在引用的时候不能加()
                fullName(){
                    console.log("getter")
                    return this.name1+'-'+this.name2
                }
                */
                }
            }
        })
    </script>
  • 监视属性

当监视属性变化时,回调函数自动调用,进行相关操作;监视属性必须存在(比如isHot不能随便被不存在的abc所代替),才能进行监视。(但不会报错,如果不存在);监视有两种写法,见下面代码

    <div id="root">
        <h2>今天天气很{{info}}</h2>
        <button @click="change">切换</button>
        <!-- 绑定事件时@xxx=‘yyy’,yyy可以写一些简单的语句 -->
        <!-- <button @click="isHot=!isHot">切换</button> -->
    </div>
    <script>
        Vue.config.productionTip = false
        var vm = new Vue({
            el: '#root',
            data: {
                isHot: true
            },
            computed: {   //使用计算属性
                info() {
                    return this.isHot ? 'hot' : 'cold' //isHot是true就‘hot’,不是就‘cold’
                }
            },
            methods: {   //事件处理
                change() {
                    this.isHot = !this.isHot  //取反
                }
            },
            watch: {   //监视属性,监视改动,不仅可以监视data中的值,也可以监视info
                isHot: {
                    immediate: true,//初始化时使handler调用一下
                    //handler在isHot发生改变时被调用
                    handler(newValue, oldValue) {
                        console.log("isHot 被修改了", newValue, oldValue)
                    }
                }
                
                 // //isHot简写条件,只有handler
                // isHot(newValue, oldValue){
                //     console.log("isHot 被修改了", newValue, oldValue)
                // }
                
            }
        })

        // //另一种监视方法
        // vm.$watch('isHot', {
        //     handler(newValue, oldValue) {
        //         console.log("isHot 被修改了", newValue, oldValue)
        //     }
        // })

        //简写,不能写成箭头函数
    //   vm.$watch('isHot',function(newValue, oldValue){
    //               console.log("isHot 被修改了", newValue, oldValue)
    //              })
    </script>

深度监视
1,Vue中的监视属性watch默认不可以监测对象内部值的改变(一层);
2,配置deep:true可以监测到对象内部的值的改变(多层)
注意:Vue自身可以监测到对象内部值的改变,但是Vue提供的watch默认不可以;使用watch时根据数据的具体结构,决定是否采用深度监视

    <div id="root">
        <h2>今天天气很{{info}}</h2>
        <button @click="change">切换</button>
        <!-- 绑定事件时@xxx=‘yyy’,yyy可以写一些简单的语句 -->
        <!-- <button @click="isHot=!isHot">切换</button> -->
        <br>
        <h3>a的值是{{numbers.a}}</h3>
        <button @click="numbers.a++">a++</button>
        <h3>b的值是{{numbers.b}}</h3>
        <button @click="numbers.b++">b++</button>
    </div>
    <script>
        Vue.config.productionTip = false
        var vm = new Vue({
            el: '#root',
            data: {
                isHot: true,
                numbers:{
                    a:1,
                    b:1
                }
            },
            computed: {   //使用计算属性
                info() {
                    return this.isHot ? 'hot' : 'cold' //isHot是true就‘hot’,不是就‘cold’
                }
            },
            methods: {   //事件处理
                change() {
                    this.isHot = !this.isHot  //取反
                }
            },
            watch: {   //监视属性,监视改动,不仅可以监视data中的值,也可以监视info
                isHot: {   //原来是‘isHot’
                    // immediate: true,//初始化时使handler调用一下
                    //handler在isHot发生改变时被调用
                //     'numbers.a':{   //监视某个属性
                //     handler() {
                //         console.log("a被修改了")
                //     }
                // },

                //监视多级结构中所有属性的变化
                
            },
            numbers:{   //监视number
                    deep:true,//改为true会使监视注意到number中的a,b
                    handler() {
                        console.log("numbers被修改了")
                    }
                },
            },
        })

        // //另一种监视方法
        // vm.$watch('isHot', {
        //     handler(newValue, oldValue) {
        //         console.log("isHot 被修改了", newValue, oldValue)
        //     }
        // })
    </script>
计算属性和监视属性的区别: 1,计算属性能完成的功能,监视属性都能完成 2,监视属性能完成的功能,计算属性不一定能完成,例如,watch可以异步操作 (所有被Vue管理的函数最好都写成普通函数,this指向才会是vm或组件实例操作; 因此所有不被Vue管理的函数,比如定时器的回调函数,ajax的回调函数等,都写成箭头函数,this才会指向vm或组件实例对象
  • 绑定样式

绑定class
方法1:字符串写法,适用于样式类名不确定,需要动态指定(举例点击切换三个不同颜色的盒子:在div里写上:class='color',@click='change'在vue的data里面写上color:'redclass',在methods里面写上相应的点击函数
方法2:数组写法,使用要绑定的样式个数不确定,名字也不确定,可以随时在页面vue扩展工具上修改增加样式(举例一个盒子上有好几种不同的样式叠加,可以根据需要随时更换盒子上的样式:<div class='basic' :class='arr'>在data中添加arr:['a','b','c']的样式数组
方法3:对象写法,适用于要绑定的样式个数确定,名字也确定,但是要动态的决定要不要用其中的样式(举例方法2的例子:<div class='basic' :class='obj'>data中obj:{a:false,b:false}

style样式绑定
和class样式绑定差不多,只不过class换成style,但是style里面要改变的东西必须是存在的

总结
1,class样式
写法: :class=‘xxx’,xxx可以是对象数组字符串 xxx的详细信息请看上方《绑定class》这一小节
2,style样式
写法: :style:“{fontsize:xxx}”其中xxx是动态值。 :style=“[a,b]"其中a,b是样式对象

  • 渲染
    条件渲染
    1,v-if
    写法:v-if=‘表达式’;v-else-if=‘’;v-else=‘’
    适用于切换频率比较低的场景,因为它将不展示的DOM元素直接移除(注意:这三个不能断,要和相对应的div或其他的一起使用
    2,v-show
    v-show=‘表达式’ 适用于切换频率较高的场景,它不会将不使用的DOM元素删除,而是隐藏起来

举例:将一直点击按钮,点三下,某个div隐藏:<div v-show='n==3'>(使用v-if元素可能无法获取,如果要将li使用v-if实现,但代码冗余,就使用template 将li列表包裹,这样也不会破坏原有结构)

列表渲染
       v-for指令
用于展示列表数据,语法是v-for=“(item,index) in xxx” :key=“yyy”;可遍历的对象包括数组,对象,字符串,指定次数,后两个不常用

    <!-- 示例代码数组 -->
    <div id="root">
    <h2>persons</h2>
    <ul>
        <li v-for="(p,index) in persons" :key="index">
            {{p.name}}-{{p.age}}
        </li>
    </ul></div>
    <script>
        new Vue({
            el:'#root',
            data:{
                persons:[
            {id:'001',name:'张三',age:21},    //使用数组,是因为顺序不可调换,添加id
            {id:'002',name:'lucy',age:34},    //是唯一标识性,:key也是因为唯一标识性
            {id:'002',name:'deve',age:23}
            ]
            },
        })
    </script>

key的作用和原理
1,虚拟DOM中key的作用
key是虚拟DOM对象的标识,当数据发生变化时,vue会根据新数据生成新的虚拟DOM;随后Vue会进行新的虚拟DOM和旧的虚拟DOM的差异比较
2,比较规则
(1),旧虚拟DOM中找到与新虚拟DOM相同的key:若虚拟DOM内容没变,则直接复用;若变了,则生成新的真实DOM,随后替换掉之前的真实DOM
(2),旧虚拟DOM中未找到与新虚拟DOM相同的key,就创建新的真实的DOM,随后渲染到页面上。
3,用index作为key引发的问题
对数据进行逆序增加删除等破坏顺序的操作会产生没有必要的真实DOM更新,效率低下;如果结构中还包含输入类的DOM,会产生错误的DOM更新,界面会出错
4,开发中如何选择key
最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号等唯一值,如果不存在逆序的破坏性操作,仅用于渲染列表用于展示,可以使用index

列表过滤
筛选出符合条件的‘新的’列表


   
    <div id="root">
    <h2>persons</h2>
    
    <input type="text" placeholder="请输入名字" v-model="keywords"> 
    <ul>
        <li v-for="(p,index) in filPersons" :key="id">
            {{p.name}}-{{p.age}}
        </li>
    </ul></div>
    <script>
        //用监视属性进行列表过滤
        // new Vue({
        //     el:'#root',
        //     data:{
        //         keywords:'',
        //         persons:[
        //     {id:'001',name:'马冬梅',age:21},   
        //     {id:'002',name:'周冬雨',age:34},    
        //     {id:'003',name:'周杰伦',age:23},
        //     {id:'004',name:'温兆伦',age:23}
        //     ],
        //     filPersons:[]
        //     },
        //     watch:{
        //         keywords:{
        //             immediate:true,
        //             handler(val){
        //                 this.filPersons=this.persons.filter((p)=>{
        //                     return p.name.indexOf(val)!=-1
        //                 })
        //             }
        //         }
        //     }
        // }
    
        // )

        //计算属性
        new Vue({
            el:'#root',
            data:{
                keywords:'',
                persons:[
            {id:'001',name:'马冬梅',age:21},   
            {id:'002',name:'周冬雨',age:34},    
            {id:'003',name:'周杰伦',age:23},
            {id:'004',name:'温兆伦',age:23}
            ]
            },
           computed:{
            filPersons(){
                return this.persons.filter((p)=>{
                    return p.name.indexOf(this.keywords)!=-1
                })
            }
           }
        }
    
        )

    
    </script>

列表排序

  
    <div id="root">
    <h2>persons</h2>
    
    <input type="text" placeholder="请输入名字" v-model="keywords"> 
    <button @click="sorttype=2">年龄升序</button>
    <button @click="sorttype=1">年龄降序</button>
    <button @click="sorttype=0">原顺序</button>
    <ul>
        <li v-for="(p,index) in filPersons" :key="id">
            {{p.name}}-{{p.age}}
        </li>
    </ul></div>
    <script>

      
        //计算属性
        new Vue({
            el:'#root',
            data:{
                keywords:'',
                sorttype:0,//0是原顺序,1是降序,2升序
                persons:[
            {id:'001',name:'马冬梅',age:21},   
            {id:'002',name:'周冬雨',age:34},    
            {id:'003',name:'周杰伦',age:23},
            {id:'004',name:'温兆伦',age:29}
            ]
            },
           computed:{
            filPersons(){
                const arr=this.persons.filter((p)=>{
                    return p.name.indexOf(this.keywords)!=-1
                })
                
                
            //判断是否需要排序
            if(this.sorttype){
                    arr.sort((p1,p2)=>{
                        return this.sorttype===1?p2.age-p1.age:p1.age-p2.age//p2-p1降序
                    })
                }
            return arr
            }

               

           }
        }
    
    )

    
    </script>

  • vm的数据监视
    1,vue会监视data中的所有层次的数据
    2,如何检测对象中的数据
<script>

        //vue如何监测对象

        //这个基本的模拟vue的监测属性,与真正vue的相比还差在:
        //控制台搜索只能vm._data.name,不能将_data忽略,另外只能监视对象的第一层



        let data={
            name:'shangguigu',
            address:'csdn'
        }

        //创建一个监视的实例对象,用于监视data中属性的变化
        const obs=new Observer(data)
        console.log(obs)
        //准备一个vm实例对象
        let vm={}
        vm._data=data=obs  //_data数据代理

        function Observer(obj){
            //汇总对象中所有的属性形成一个数组
            const keys=Object.keys(obj)
            //遍历
            keys.forEach((k)=>{
                Object.defineProperty(this,k,{ //使用this不会改变原数据,从而死循环
                    //使用setter和getter是因为监视必须,使用定时器什么的监视会引起死循环
                    get(){
                        return obj[k]
                    },
                    set(val){
                        console.log('${k}被改了,接下来是解析模板,生成虚拟DOM.....')
                    }
                })
            })
        }
    </script>

通过setter实现监视,且要在new Vue时就要传入要监视的数据:对象后追加的属性,vue默认不做响应式处理;如果要响应,使用set()

    <div id="root">
        <h1>学校信息</h1>
        <h2>学校名称{{name}}</h2>
        <h2>学校地址{{address}}</h2><hr>

        <h1>学生信息</h1>
        <button @click="addSex">添加性别属性,默认为男</button>
        <h2>姓名{{student.name}}</h2>
        <h2 v-if="student.sex">性别{{student.sex}}</h2>
        <h2>盆友们</h2>
        <ul>
            <li v-for="(f,index) in student.friends" :key="index">
                {{f.name}}-{{f.age}}
            </li>
        </ul>
        <hr>
    </div>

    <script>
        const vm=new Vue({
            el:'#root',
            data:{
                name:'BILIBILI',
                address:'csdn',
                student:{
                    name:'tom',
                    age:{
                        rAge:23,
                        sAge:18
                    },
                    friends:[
                        {name:'jerry',age:32},
                        {name:'tony',age:42}
                    ]
                }
            },
            methods: {
                addSex(){
                    //用于后添加,使用其他方法可能不会有setter和getter,
                    //局限:只能添加到data中的某个对象中,不可以直接在vm或data中添加
                    // Vue.set(this.student,'sex','男')
                    this.$set(this.student,'sex','女')     //
                }
            },
        })
    </script>

3,监测数组中的数据
通过包裹数组更新元素的方法实现:调用原生对应方法对数组进行更新;更新解析模板,进而更新页面
4,vue中修改数组中某个元素:使用一下API(push,pop等);Vue.set()或vm.$set() (注意这两个不能给vm或vm的跟数据对象_data添加属性)

 <div id="root">
       <h2>爱好</h2>
       <button @click="click">点击增加爱好</button>
       <ul>
        <li v-for="(h,index) in hobby" :key="index">
            {{h}}
        </li>
       </ul>
    </div>

    <script>
        const vm=new Vue({
            el:'#root',
            data:{
               hobby:['学习','跑步','游泳']
            },
            methods: {
                click(){
                    //不可以通过数组的索引值赋值
        //在数组中改变要用push,splice,pop等,这里没有用到原型,vue将数组的变更方法进行包裹
        //也可以用set,详情看vue官网
                    vm.hobby.splice(0,1,'打台球')   
                }
            },
        })
    </script>

tips:在要修改元素时用到setter的过程叫数据劫持

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值