Vue全家桶(一)

今天写了一天的时间,麻烦读者怀一颗感恩的心阅读哈~小编提前感谢大家咯


小编今天为大家推出一期vue全家桶续集~按照下述的xmind来哦,有兴趣的童鞋可以提前预习一下。。。
请添加图片描述

一.vue框架

1.项目的框架模式(MV*)

1.1.MVC架构模式

1.MVC的出现用在后端(全栈时代)。
2.M:model,模型,主要完成业务功能,在数据库相关的项目中,数据的增删改查
V:view,视图,主要负责数据的显示(html+css)。
C:controller,控制器,主要负责每个业务的核心流程,在项目中体现在路由以及中间件上。
在这里插入图片描述
3.优缺点:

  • 优点:
    耦合度低、复用性高、生命周期成本低、部署快、可维护性高、有利于软件工程化管理。
  • 缺点
    由于模型和视图分离,这样给调试应用程序带来困难。

1.2MVP架构模式

1.MVP:Model View Presenter,分别表示数据、视图和发布层。是MVC架构的一种演变。
2.M:model,模型,主要完成业务功能,在数据库相关的项目中,数据的增删改查
V:view,视图,主要负责数据的显示(html+css)。
p:Presenter负责业务流程的逻辑处理,Presenter是从Model中获取数据并提供给View层,Presenter还负责处理后端任务。
在这里插入图片描述
3.MVP模式与MVC模式的区别:
MVP模式中的View不直接使用Model,而MVC模式中View可以绕过Controller,从Model中直接读取数据。

1.3MVVM架构模式

1.MVVM是Model-View-ViewModel,MVVM模式与MVP模式相似。唯一区别是MVVM模式采用的是数据双向绑定
在这里插入图片描述

1.4总结

1.vue采用的是MVVM模式,M-V-VM,M是数据,V是视图,VM负责M与V相互通信。
2.架构是一种思维方式,是一种思考问题解决问题的思维。目的解决编程过程中模块内部高内聚、模块与模块直接的低耦合、可维护性、易测试等。
3.架构有利于做好代码的分工,配合

二.vue框架的核心

1.vue框架的核心:数据驱动和组件化。

  • 数据驱动:数据的变化驱动页面发生变化,不用操作DOM。(一定要切记幺,是不是有的宝宝一冲动,就想操作Dom啦)
  • 组件化:把页面封装成若干个组件,把组件进行拼装,让页面的复用性达到最高。

三.初识vue框架(vue官网)

温馨提示♥:要多看官方API,英语基础弱的小伙伴,可以直接看代码示例,直接上代码~

铺垫:
1.vue的作者:尤雨溪(华人),前Google员工;
2.vue是构建数据驱动的web应用开发框架;
3.vue是一套用于构建用户界面的渐进式框架;(渐进式:可以在原有的系统上开发,把一两个组件改用vue实现,也可以整个用vue全家桶开发,不会做职责之外的事。)
4.vue被设计为可以自顶向上增量开发逐层应用;( 自顶向上增量开发:先写一个基础页面,把基础的东西写好,再逐一添加功能和效果,由简单到繁琐的过程。)
5.vue的核心只关注视图层;
6.vue框架的核心:数据驱动组件化
7.vue不支持IE8及以下版本。

3.1vue框架

3.1.1理解

1.写好HTML模板,声明式地告知vuejs库,数据显示在何处,在vue对象中处理数据,不用做DOM操作(vuejs库会帮我们做哦)即new出来一个Vue实例,传一堆配置参数,就可以控制一片html。
在这里插入图片描述

3.1.2名词解释

  • 数据驱动:通过控制数据的变化来改变(驱动)DOM,背后使用了观察者模式,靠数据的变化来控制页面的变化。
  • 声明式渲染:告知程序(vue框架),在何处渲染什么数据。
  • 数据绑定:是通过数据劫持观察者模式的方式来实现的。
    ①数据劫持:vue2.x使用Object.defineProperty();,vue3使用的是Proxy。把普通JavaScript对象(json)传入Vue实例作为data选项,Vue将遍历此对象所有的属性,并使用Object.defineProperty()把这些属性全部转为getter/setter。
    在这里插入图片描述
class MyVue {
    constructor(obj) {
        // 定义一个属性保存原始的html代码(带着双括号等vue的指令)
        this.sourc`e`HtmlStr = document.querySelector(obj.el).innerHTML;

        // 订阅(Observer)
        // 在html里查找什么地方使用 数据 key
        // 此处本该使用循环,去订阅所有数据的变化
        // 但是,现在算了,只考虑msg的变化。
        let o = new Observer();
        o.addSubsciber((what) => {
            this.render(); //此处只是模拟,
        });

        // 把obj的根属性作为vue对象的属性(属性名前面加上了$)
        for (let key in obj) {
            this["$" + key] = obj[key];
        }

        // 一、数据劫持(把obj里的data里的每个属性,增加setter和getter)。
        for (let key in obj.data) {
            Object.defineProperty(this, key, {
                set: function(newVal) {
                    this["_" + key] = newVal;
                    this.$data[key] = newVal;
                    // 能够感知到当前属性被改了。
                    // console.log(key+"被改了");
                    // 利用观察者模式,进行发布了(修改dom)。
                    o.publish(newVal);
                },
                get: function() {
                    return this["_" + key];
                }
            });
        }

        // 二、渲染
        this.render();
    }

    render() {
        // 操作dom       
        let newHtmlStr = this.sourceHtmlStr;
        for (let key in this.$data) {
            // newHtmlStr = newHtmlStr.replace(/{{msg}}/g,this.$data.msg);
            newHtmlStr = newHtmlStr.replace(new RegExp("{{" + key + "}}", "g"), this.$data[key]);
        }
        document.querySelector(this.$el).innerHTML = newHtmlStr;
    }

}

class Observer {
    constructor() {
            this.arr = [];
        }
        // 添加订阅者
    addSubsciber(cb) {
            this.arr.push(cb);
        }
        // 删除订阅者
    removeSubscriber(cb) {
            let index = this.arr.indexOf(cb);
            this.arr.splice(index, 1);
        }
        // 发布
    publish(what) {
        this.arr.forEach(item => {
            item(what);
        });
    }
}

②观察者模式(发布订阅模式):
目的:当属性发生变化时,所有使用该数据的地方跟着变化。(响应式)

// 发布订阅者模式
let observer = {
    arr:[],//存储的是所有的订阅者
    // 添加订阅者
    addSubscriber:function(fn){
        this.arr.push(fn);
    },
    // 发布:
    publish:function(what){
        this.arr.forEach(fn=>{
            fn(what);
        });
    }
}
  • 组件:页面中的一个个ui部件,写在components文件夹下。
  • 页面组件:项目中的一个个页面整体,写在views/pages文件夹下。
  • 单页面应用(SPA):single page application,整个项目中只有一个HTML页面(文件),首次加载是,把所有的html、css、js全部加载下来。通过操作dom的删除和创建(添加)来完成页面的切换。
  • 单页面文件:single-file components,文件扩展名为 .vue 的 (单文件组件) 。(这点小编还不太清楚,弄懂了及时告诉你们哦~)

四.组件

组件封装的是完整的功能(包括:html、css、js),而函数只封装js(逻辑)。

4.1概念

1.组件是自定义标签,vueJS提供的组件可以让程序员自定义标签,对页面进行模块化。每个标签中包含html、css、js。
2.vue的组件是一个vue对象,vue对象的配置项,在vue组件中可以使用。
注:

  • 没有el属性;
  • template:HTML模板代码,只能有一个根标签;
  • data:必须是个函数;​ 组件中的 data 必须是一个函数,且要返回object,只有这样,每个实例(vue组件对象)就可以维护一份被返回对象的独立的拷贝,否则组件复用时,数据相互影响,也就是说,组件的作用域是独立的。
    ​ 简单回答:如果不是函数,那么,复用的组件的data共享同一块内存空间。

一个完整的标签名格式: <标签名 属性名=“属性值" 事件=”函数“>内容</标签名>
根据HTML的标签理解组件,我也是根据标签的格式,来说组件啦~

4.2组件的基本使用(标签名)

4.2.1定义组件

(一)标准版

let 组件变量名= Vue.extend({
        template:'<div class="header">{{msg}},我是header组件</div>'
        data:function(){
			return {
				msg:”hi”
			}
		},
  });

(二)简化写法

let 组件变量名={
        配置项
}; 

4.2.2注册组件

  • 全局注册component:在任何vue对象里都可以使用。
Vue.component('组件名',组件变量名);
  • 局部注册components:只能在当前vue对象(组件)里使用。
//在vue对象的components选项里进行注册
new Vue({
     el:
     components:{
    	 组件名:组件变量名
     }     
});

4.2.3使用组件

组件就是自定义标签,使用组件就和使用官方标签是一样的。直接写名称就可以。

注意:如果组件定义时变量为驼峰命名,则在使用时,使用羊肉串的方式。双标签和单标签都可以的吆~
<组件名></组件名>
<组件名/>

4.2.4组件嵌套

把一个组件的标签写在另外一个组件的template中。
eg:父组件中嵌套了子组件

 //子组件 
  let myComSon = {
        template:"<div>我是son里的div:{{msg}}</div>",    
        data:function(){
            return {
                msg:"hi:son"
            }
        }
    };

   //父组件 
    let myComParent = {
        template:`<div>
                        <p>我是p:{{msg}}</p>
                        <my-com-son></my-com-son>                    
                    </div>`,
        data:function(){
            return {
                msg:"hi"
            }
        },
        components:{
            // 局部注册了另外一个组件
            "my-com-son":myComSon
        }    
    };

4.2.5组件编写方式 vs Vue实例的区别

来自小编的福利:小驼峰和大驼峰
小驼峰:除过首字母不大写,其余单词首字母大写;
大驼峰:所有单词首字母大写。

  • 组件名不可和HTML官方的标签名同名,组件名如果如果使用小驼峰,那么使用时,用短横线(羊肉串)或者组件名首字母大写;
  • 组件没有el选项,只有根实例存在el,组件里使用template定义模板;
  • 组件模板(html代码)只能有一个根标签;
  • 组件中的data必须是一个函数。实例中不是函数。

4.3组件的属性(标签的属性)

1.使用props来完成组件属性的声明。props是外部给组件传入的数据。而组件的data是组件内部的数据。

4.3.1使用Props传递静态数据

①在组件内部增加配置项props来声明组件里的属性。props里面可以声明多个属性。所以是一个数组。

let myComParent = {
        props:["name","sex"], //声明了两个自定义属性
        template:`<div>
                        <p>我是p:{{msg}}</p>     
                        <p>人的信息:</p>             
                        <p>姓名:{{name}}</p>             
                        <p>性别:{{sex}}</p>             
                    </div>`,
        data:function(){
            return {
                msg:"hi"
            }
        } 
    };

②使用组件时,给属性传入数据:

<!-- 使用组件时,给属性传入值,传入的值,就可以在组件内部使用 -->
<my-com-parent name="张三疯他哥" sex=""></my-com-parent>

③总结
封装组件和封装函数进行类比:
●在组件内部用props声明的属性,相当于封装函数时声明的形参;
●使用组件时,相当于调用函数,传递实参。

4.3.2使用Props传递动态数据

即是给组件的属性v-bind(绑定动态数据)

<my-com-parent v-bind:name="name" sex=""></my-com-parent>	

如果想把对象的所有属性作为prop进行传递,可以使用不带任何参数的v-bind(即用v-bind而不是v-bind:prop-name).

todo: {
  text: 'Learn Vue',
  isComplete: false
}
<todo-item  v-bind="todo"></todo-item>

//等价于:
<todo-item 
  v-bind:text="todo.text"
  v-bind:is-complete="todo.isComplete"

></todo-item>

奇葩情况:
在JavaScript中对象和数组是通过引用传入的(传的是地址),所以对于一个数组或对象类型的prop来说,在子组件中改变这个对象或数组苯磺酸呢将会影响到父组件的状态(data),相当于函数的形参是引用类型。

4.3.3 Props验证

vueJS提供了对属性类型的验证、属性默认值、是否必须等。

这时props不能使用数组,而需要使用对象。

props:{
            "name":{
                type:String, //限制name属性的类型是字符串
                required:true //限制name属性是必须传入值的。
            },
            "sex":[String,Number], //限制sex属性的值可以为字符串,也可以为数字
            "age":{
                type:Number, //限制age属性的类型是数字型
                default:10 // age属性的默认值是10 。如果没有给age传值,那么age就是10。
            },
            "isadult":Boolean
        },

4.3.4单向数据流

Prop 是单向绑定的:当父组件的属性(数据)变化时,将传导给子组件,但是反过来不会。这是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解。
另外,每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台给出警告。

4.4.组件的事件

4.4.1绑定事件

  • HTML(标签)里的绑定方式:v-on
  • JS(Vue)里绑定方式: vue对象.$on(“事件名”)

4.4.2触发事件

vue对象.$emit(“事件名”,参数);

//子组件:
Vue.component('button-counter',{
	template: "<input type='button' v-on:click='incrementCounter' v-model='counter' />",
	data:function(){
		return {
			counter:0
		}
	},
	methods:{
		incrementCounter:function(){
			this.counter += 1
			this.$emit('increment')
		}
	}
});

//父组件:

<div id="app1">
    <p>{{ total }}</p>
    <button-counter v-on:increment="incrementTotal"></button-counter>
</div>

var app1 = new Vue({
	el: '#app1',
	data:{
		total:0
	},
	methods:{
		incrementTotal:function(){
			this.total += 1;
		}
	}
});

4.5组件的内容(插槽)

  1. 组件的内容就是标签的innerHTML。vueJS里使用**Slot(插槽)**分发内容。
  2. 将父组件的内容(DOM)放到子组件指定的位置叫作内容分发。
  3. 分类

4.5.1单个插槽

 //子组件
 let person = {      
        template:`<div>
                        <hr/>
                            <p>我是上p</p>
                            <slot></slot>
                            <p>我时下p</p>
                        <hr/>
                    </div>`
    };

//父组件:
   <div id="app">
        <person>
            <div>我是div</div>
        </person>        
    </div>

    new Vue({
        el:"#app",
        components:{
            person
        }
    });

4.5.2具名插槽

如果父级给子级传来好多DOM(HTML元素),而且需要把不同的DOM放在子组件不同位置时,需要给slot起名字。利用slot元素的特殊属性name来配置如何来分发内容。

<slot name="插槽名"></slot>
//子组件
     let person = {      
        template:`<div>
                        <hr/>
                            <p>我是上p</p>
                            <slot name="s1"></slot>
                            <p>我是中p</p>
                            <slot name="s2"></slot>
                            <p>我是下p</p>
                        <hr/>
                    </div>`
    };
//父组件
  <div id="app">
        <person>
            <div slot="s1">我是div1</div>
            <div slot="s2">我是div2</div>
        </person>        
    </div>
   new Vue({
        el:"#app",
        components:{
            person
        }
    });

4.5.3编译作用域

父组件模板的内容在父组件作用域内(父组件对应的对象的作用域)编译;子组件模板的内容在子组件作用域内编译。

//子组件
let person = {      
        template:`<div>
                        <hr/>
                            <p>我是上p:{{t}}</p>
                            <p>我是下p</p>
                        <hr/>
                    </div>`,
        data(){
            return{
            	t:"我是子组件的数据"
        	}
        }
    };
    
//父组件:
  <div id="app">
        <input :value="msg" />         
        <person v-show="s">
            <p>{{msg}}</p>
            <div>我是div1:{{msg}}</div>
        </person>
  </div>

    new Vue({
        el:"#app",        
        data:{
            msg:"hi",
            s:true
        },
        components:{
            person
        }
    });

扩展:有余力的小可爱阔以自行研究一下作用域与插槽!

4.6组件(间)的通信

vue组件之间的通信(传递数据)是必然的,依据vue组件之间的关系(父子,兄弟,或者无关组件)会有不同的做法:

  • 父子组件:props /ref/s $emit
  • 父子、隔代、兄弟组件通信 :EventBus $emit / $on
  • 集中管理,适用于所有场景:$root
  • 适用于所有场景:Vuex,路由
    下面为大家一一讲解,路由,Vuex后续讲道router、Vuex详讲解。

4.6.1父子组件

父->子:props,refs,也叫正向传值;
子->父:事件,逆向传值。

  • 父组件给子组件传值

在这里插入图片描述
props传值:就是上面所提到的prop动态传值。
①子组件

<template>
  <div>
      <!-- 使用 -->
      homezi--{{title}}---{{num}}--{{sex}}
  </div>
</template>

<script>
export default {
    // 子组件设置好了接收
    props:["title","num",'sex']
}
</script>

②父组件

<template>
  <div>
      home
      <!-- 在子组件被调用的地方 进行传递 -->
      <Homezi title="我是title" num="我是num" sex="我是sex"/>
  </div>
</template>

<script>
import Homezi from "./homezi.vue"
export default {
    components:{
        Homezi
    }
}
</script>
  • refs传值: **用标签的方式使用组件,实际就是创建了组件对象。**只要拿到组件对象,那么组件对象中的methods就可以使用。refs是vue中获取dom的一种方式,dom也就是标签,标签就是组件对象。即拿到了dom,就相当于拿到了组件对象。(这句话细细品味幺,开动你们的小脑筋)

如果某个元素使用ref属性,那么,在vue对象里,就能用this.$refs 访问。可以认为是给元素增加了个id属性,在vue里就可以操作该dom了。

格式:

    <p ref = "pId"> {{msg}}</p>

 methods:{
     testf:function(){
       	this.$refs.pId.innerHTML = "hi";
     }
}

示例:

 <!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div class="app">
        <input type="text" :value="str" ref="txt"> <input type="button" value="测试" @click="fn">
        <parent ref="par"></parent>
    </div>
    <script src="vue.js"></script>
    <script>
        // 定义子组件
        let son = {
                template: ` <div>
            <p>我是子组件</p>
          </div>`
            }
            // 定义组件
        let parent = {
            template: `
           <div>
            <p>我是父组件</p>
            <p>{{str1}}</p>
            <son></son>
          </div>`,
            data: function() {
                return {
                    str1: "hi,我是str1"
                }
            },
            components: {
                son
            }

        };

        let vm = new Vue({
            el: ".app",
            // 注册组件
            components: {
                parent: parent
            },
            data: {
                str: "hi"
            },
            methods: {
                fn() {
                    this.$refs.txt.type = "button";
                    this.$refs.par.str1 = "哈哈哈";
                    // console.log(this.$refs.par.str1);
                }
            }
        })
    </script>
</body>

</html>

4.6.2兄弟组件

4.6.2.1事件总线events-bus

1.vue-bus实质就是创建一个vue实例,通过一个空的vue实例作为桥梁实现vue组件间的通信。它是实现非父子组件通信的一种解决方案。
2.步骤:假如B组件给A组件传值,则B组件触发,A组件绑定事件

①单独new一个Vue空对象: let bus= new Vue();
②在组件A里,绑定一个自定义事件(相当于定义了一个自定义事件):
bus.$on(‘eclick’,target => {
console.log(target) 
})

③在组件B里,触发事件
bus.$emit(‘eclick’,“b传给a的”);

3.示例

// 定义一个vue对象(作为事件总线的对象)
let bus = new Vue();

let myCom1 = {
    template:`
        <div>
            <hr>
            组件com1
            <hr>
        </div>
    `,
    created(){
        // 注册了一个事件
        bus.$on("eclick",(target)=>{
            console.log(target);
        });        
    }
}

let myCom2 = {
    template:`
        <div>
            <input type="button" value="  传 " @click="fn" />
        </div>
    `,
    methods:{
        fn(){
            //触发事件
            bus.$emit("eclick","hello");
        }
    }
}

Vue.component("my-com1",myCom1);
Vue.component("my-com2",myCom2);

new Vue({
    el:"#app"
});
4.6.2.2集中管理($root)

把数据存到根实例的data选项,其他组件直接修改或者使用。
1.定义:

new Vue({
  data:{a:1}
})

2.使用

//子组件内部
this // 子组件本身
this.$root // vm 根实例
this.xx //组件内部数据
this.$root.a //根实例数据

4.6.3动态组件

有的时候,在不同组件之间进行动态切换是非常有用的。即页面的某个位置要显示的组件是不确定的,是会变化的。

//vue中使用的方式实现
<component :is="组件名变量">

示例:

<div id="app">
        <span @click="show(0)">娱乐</span>|<span  @click="show(1)">八卦</span>|<span @click="show(2)">体育</span>
        <div>
            <component :is="currCom"></component>
        </div>
</div>

let yuLe = {
    template:"<div>娱乐新闻</div>"
}
let eightGua = {
    template:"<div>八卦新闻</div>"
}
let sports = {
    template:"<div>体育新闻</div>"
}

new Vue({
    el:"#app",
    data:{
        currCom:"yuLe",
        coms:["yuLe","eightGua","sports"]
    },
    methods:{
        show(index){
            this.currCom = this.coms[index];
        }
    },
    components:{
        yuLe,eightGua,sports
    }
});

4.6.4单文件组件

1.构成:template+script+style
2.后缀名为.vue.
3.定义: 把一个组件的所有代码(HTML模板,样式,js(vue对象))写在一个文件里,扩展名是.vue。一个文件里就只有一个组件。这就是单文件组件。

<template>
      HTML代码
</template>

<script>
      vue对象 (使用模块化导出vue对象):可以使用es6的写法
</script>

<style scoped> //scoped: 表示局部作用域,表示当前style标签的样式只会应用在当前vue文件里的模板里
     样式
</style>

eg:

<template>
     <p>{{msg}}</p>
</template>

<script>
	export default {
        
        data(){
 		 return {  
 		 	msg:”hello” 
 		 }
 	   }
	}
</script>
<style scoped>
	p{
          color:red;
          font-size:12px
    }
</style>

4.6.5单页面应用(SPA)

1.定义:SPA:single page application,单页面应用。
​整个项目就只有一个html页面(文件),首次加载时,把所有的html,css,js全部加载下来。通过操作dom的删除和创建(添加)来完成页面的切换。
2.优缺点

  • 优点:
    ①局部刷新,所以,用户体验好
    ②前后端分离
    ③页面效果会比较炫酷(比如切换页面内容时的转场动画)

  • 缺点:
    ①不利于seo
    ②导航不可用,如果一定要导航需要自行实现前进、后退。
    ③初次加载时耗时多
    ④页面复杂度提高很多
    3.SPA和MPA的区别

  • SPA: single page application
    只有一个主页面的应用,浏览器一开始要加载所有必须的 html, js, css。所有的页面内容都包含在这个所谓的主页面中。但在写的时候,还是会分开写(页面片段),然后在交互的时候由路由程序动态载入,单页面的页面跳转,仅刷新局部资源。vue后来做了改进,有些组件按需加载

  • MPA:multiple page application
    一个应用中有多个页面,页面跳转时是整页刷新。

插槽页面模式多页面模式(MPA Multi-page Application)单页面模式(SPA Single-page Application)
页面组成多个完整页面, 例如page1.html、page2.html等由一个初始页面和多个页面模块组成, 例如:index.html
公共文件加载跳转页面前后,js/css/img等公用文件重新加载js/css/img等公用文件只在加载初始页面时加载,更换页面内容前后无需重新加载
页面跳转/内容更新页面通过window.location.href = "./page2.html"跳转通过使用js方法,append/remove或者show/hide等方式来进行页面内容的更换
数据的传递可以使用路径携带数据传递的方式,例如:http://index.html?account=“123”&password=123456"",或者localstorage、cookie等存储方式直接通过参数传递,或者全局变量的方式进行,因为都是在一个页面的脚本环境下
用户体验如果页面加载的文件相对较大(多),页面切换加载会很慢页面片段间切换较快,用户体验好,因为初次已经加载好相关文件。但是初次加载页面时需要调整优化,因为加载文件较多
场景适用于高度追求高度支持搜索引擎的应用高要求的体验度,追求界面流畅的应用
转场动画不容易实现容易实现

单页面模式:相对比较有优势,无论在用户体验还是页面切换的数据传递、页面切换动画,都可以有比较大的操作空间 多页面模式:比较适用于页面跳转较少,数据传递较少的项目中开发,否则使用cookie,localstorage进行数据传递,是一件很可怕而又不稳定的无奈选择。

今天先为大家分享到这,想听后续,可以点击关注☺,luckyPian才有动力持续为您更新~
文末彩蛋—实战项目:基于Java+SpringBoot+Vue前后端分离电商项目

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值