前端学习之旅——第一周

0.前言

实习的岗位是前端开发,在企业导师的指导下,在第一周按照以下几个步骤进行学习,主要是学习vue框架,了解一些基础,相当于是入门级别。
在学习之前,了解一下前端的MVVM框架吧。

1.下载最新的node.js

使用vue,安装nodejs是基础。这里的下载、安装、配置是参考这篇博客的。步骤还是比较详细清楚的。也可参考这篇博客,这里是下载的zip,省略了安装过程,主要在配置上。

2.下载最新的yarn

这个下载安装还是比较简单的,有多种安装方式,但是建议从官网上下载安装,具体可参考这篇博客

3.查资料了解yarn和npm的区别

首先,yarn和npm都属于js包管理工具,都可以安装包或者模块

3.1.官网文档

npm:https://www.npmjs.cn/
yran:https://yarn.bootcss.com/

3.2.npm

npm是Node.js能够如此成功的主要原因之一。npm团队做了很多的工作,以确保npm保持向后兼容,并在不同的环境中保持一致。
npm是围绕着语义版本控制(semver)的思想而设计的,下面是从他们的网站摘抄过来的:

给定一个版本号:主版本号.次版本号.补丁版本号, 以下这三种情况需要增加相应的版本号:

  • 主版本号: 当API发生改变,并与之前的版本不兼容的时候
  • 次版本号: 当增加了功能,但是向后兼容的时候
  • 补丁版本号: 当做了向后兼容的缺陷修复的时候

npm使用一个名为package.json的文件,用户可以通过npm install --save命令把项目里所有的依赖项保存在这个文件里。
例如,运行npm install --save lodash会将以下几行添加到package.json文件中。

"dependencies": {
    "lodash": "^4.17.4"
}

请注意,在版本号lodash之前有个^字符。这个字符告诉npm,安装主版本等于4的任意一个版本即可。所以如果我现在运行npm进行安装,npm将安装lodash的主版本为4的最新版,可能是 lodash@4.25.5(@是npm约定用来确定包名的指定版本的)。你可以在此处查看所有支持的字符:https://docs.npmjs.com/misc/semver

3.3.npm的不足

(1)npm install的时候巨慢。特别是新的项目拉下来要等半天,删除node_modules,重新install的时候依旧如此。
(2)同一个项目,安装的时候无法保持一致性。由于package.json文件中版本号的特点,下面三个版本号在安装的时候代表不同的含义。 “5.0.3”表示安装指定的5.0.3版本,“~5.0.3”表示安装5.0.X中最新的版本,“^5.0.3”表示安装5.X.X中最新的版本。这就麻烦了,常常会出现同一个项目,有的同事是OK的,有的同事会由于安装的版本不一致出现bug。

"5.0.3",
"~5.0.3",
"^5.0.3"

(3)安装的时候,包会在同一时间下载和安装,中途某个时候,一个包抛出了一个错误,但是npm会继续下载和安装包。因为npm会把所有的日志输出到终端,有关错误包的错误信息就会在一大堆npm打印的警告中丢失掉,并且你甚至永远不会注意到实际发生的错误。
(4)模块的依赖问题。
npm模块的依赖关系比如说、项目模块依赖是图中描述的,@1.2.1代表这个模块的版本。在你安装A的时候需要安装依赖C和D,很多依赖不会指定版本号,默认会安装最新的版本,这样就会出现问题:比如今天安装模块的时候C和D是某一个版本,而当以后C、D更新的时候,再次安装模块就会安装C和D的最新版本,如果新的版本无法兼容你的项目,你的程序可能就会出BUG,甚至无法运行。

3.4.yarn

“Yarn是由Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具 ,正如官方文档中写的,Yarn 是为了弥补 npm 的一些缺陷而出现的。”

yarn一开始的主要目标是解决由于语义版本控制而导致的npm安装的不确定性问题。

每个yarn安装都会生成一个类似于npm-shrinkwrap.json的yarn.lock文件,而且它是默认创建的。除了常规信息之外,yarn.lock文件还包含要安装的内容的校验和,以确保使用的库的版本相同。下图是yarn.lock文件格式:
yarn.lock文件格式这个文件已经把依赖模块的版本号全部锁定,当执行yarn install的时候,yarn会读取这个文件获得依赖的版本号,然后依照这个版本号去安装对应的依赖模块,这样依赖就会被锁定,以后再也不用担心版本号的问题了。其他人或者其他环境下使用的时候,把这个yarn.lock拷贝到相应的环境项目下再安装即可。
注意:这个文件不要手动修改它,当使用一些操作如yarn add时,yarn会自动更新yarn.lock。

由于yarn是崭新的经过重新设计的npm客户端,它能让开发人员并行化处理所有必须的操作,并添加了一些其他改进,这使得运行速度得到了显著的提升,整个安装时间也变得更少。

3.5.yarn的优点

(1)速度快 。速度快主要来自以下两个方面:

  • 并行安装:无论 npm 还是 yarn 在执行包的安装时,都会执行一系列任务。npm 是按照队列执行每个 package,也就是说必须要等到当前 package 安装完成之后,才能继续后面的安装。而 yarn 是同步执行所有任务,提高了性能。
  • 离线模式:如果之前已经安装过一个软件包,用yarn再次安装时之间从缓存中获取,就不用像npm那样再从网络下载了。

(2) 安装版本统一:为了防止拉取到不同的版本,Yarn 有一个锁定文件 (lock file) 记录了被确切安装上的模块的版本号。每次只要新增了一个模块,Yarn 就会创建(或更新)yarn.lock 这个文件。这么做就保证了,每一次拉取同一个项目依赖时,使用的都是一样的模块版本。npm 其实也有办法实现处处使用相同版本的 packages,但需要开发者执行 npm shrinkwrap 命令。这个命令将会生成一个锁定文件,在执行 npm install 的时候,该锁定文件会先被读取,和 Yarn 读取 yarn.lock 文件一个道理。npm 和 Yarn 两者的不同之处在于,Yarn 默认会生成这样的锁定文件,而 npm 要通过 shrinkwrap 命令生成 npm-shrinkwrap.json 文件,只有当这个文件存在的时候,packages 版本信息才会被记录和更新。
(3)更简洁的输出:npm 的输出信息比较冗长。在执行 npm install 的时候,命令行里会不断地打印出所有被安装上的依赖。相比之下,Yarn 简洁太多:默认情况下,结合了 emoji直观且直接地打印出必要的信息,也提供了一些命令供开发者查询额外的安装信息。
(4)多注册来源处理:所有的依赖包,不管他被不同的库间接关联引用多少次,安装这个包时,只会从一个注册来源去装,要么是 npm 要么是 bower, 防止出现混乱不一致。
(5)更好的语义化: yarn改变了一些npm命令的名称,比如 yarn add/remove,感觉上比 npm 原本的 install/uninstall 要更清晰。

3.6.区别总结

  • npm 下载包的话,比如npm install,它是按照包的排序,也就是队列挨个下载,一个下载完成后,再下载另一个。
    yarn是将要下载的包进行同时下载
  • yarn 在下载模块或包时,命令行输出的信息更加简洁
  • npm版本5.0 之后,会自带package.lock.json 文件,该文件主要描述了你项目中安装的包都是哪一个版本,你再进行npm install 的话,会安装指定版本的包。
    yarn 一直都有lock 文件,功能和npm 的package.lock.json差不多。
  • 命令不同
    NPM和YARN的命令区别

3.7.参考链接

npm和yarn的区别和对比
一文看懂npm、yarn、pnpm之间的区别
我们来解释一下npm和yarn的区别
yarn的安装和使用
npm和yarn的区别,我们该如何选择?
npm和yarn的区别(包管理工具)

4.vue.cli介绍

4.1.vue入门

这里是跟着慕课网进行了一些简单的学习。

4.1.1.vue安装

官网上给了很多种安装的方式,这里采用的是最简单的一种,直接使用script引入。
vue安装其实就是下载一个vue.js文件,然后在html文件的head里使用script引用。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Vue入门</title>
	<!-- src中是vue.js的位置 -->
	<script src="./vue.js"></script>
</head>
<body>
</body>
</html>

4.1.2.挂载点、模板、实例之间的关系

vue 实例,像是以ID为依据,把div的内容接管了,改vue实例里的内容,然后以数据绑定的方式在div里显示。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Vue入门</title>
	<!-- src中是vue.js的位置 -->
	<script src="./vue.js"></script>
</head>
<body>
	<!-- 挂载点,模板,实例之间的关系 -->
	<div id="root">                             <!-- 挂载点 -->
		……
	</div>                       
	<script>
		new Vue({                               /* 实例 */
			el:"#root",                         /* 使用el将vue实例与挂载点联系起来 */
			template: '<h1>hello {{msg}}</h1>', /* 模板,也可以放在挂载点中间,即上面……的位置 */
			data:{                              /* 数据 */
				msg:"hello world!"
			}
		})
	</script>
</body>
</html>

vue实例中的属性之间要用“,”(英文的逗号)分隔开,否则会有问题。

4.1.3.实例中的数据、事件和方法

(1)数据显示在模板上的三种方法:
方法一:

<div id="root">
	<h1>{{content}}</h1>
</div>

方法二:

<div id="root">
	<h1 v-text="content"></h1>
</div>

方法三:

<div id="root">
	<h1 v-html="content"></h1>
</div>

附注
a、方法一与方法二等价。
b、方法二和方法三的区别在于,当content内容为html代码时,v-text显示的是代码本身,而v-html显示的是代码表示的效果。
例如,content:“< h1 >hello< /h1 >”时,v-text网页显示为< h1 >hello< /h1 >,而v-html网页只显示hello。
方法二效果方法三效果(2)绑定点击事件
下面这段代码可以实现点击页面上的hello,能将hello变成world。

<body>
	<div id="root">
		<div v-on:click="handleClick">{{content}}</div>
	</div>
	<script>
		new Vue({
			el:"#root",
			data:{
				content:"hello"
			},
			methods: {
				handleClick: function(){
					this.content="world"
				}
			}
		})
	</script>
</body>

注意
a、v-on:click可以设置一个点击事件,点击事件的方法在实例的methods里定义。
b、vue是面向数据的,因此这里使用this.content="world"修改content中的数据就可以实现页面上的数据更新。
c、v-on:可以替换成@,两者是等价的,即上述代码与下述代码实现的效果一致。

<body>
	<div id="root">
		<div @click="handleClick">{{content}}</div>
	</div>
	<script>
		new Vue({
			el:"#root",
			data:{
				content:"hello"
			},
			methods: {
				handleClick: function(){
					this.content="world"
				}
			}
		})
	</script>
</body>

4.1.4.属性绑定和双向数据绑定

(1)属性绑定:使用v-bind:或:
下面这个代码实现的是当鼠标放在hello world上,会显示vue实例中title的值。

<body>
	<div id="root">
		<div v-bind:title="'vue '+title">hello world</div>
	</div>
	<script>
		new Vue({
			el:"#root",
			data:{
				title:"this is hello world"
			}
		})
	</script>
</body>

效果如下:
属性绑定实现效果
注意:
可以用":“代替"v-bind:”,即下述代码与上述代码实现的效果一样。

<body>
	<div id="root">
		<div :title="'vue '+title">hello world</div>
	</div>
	<script>
		new Vue({
			el:"#root",
			data:{
				title:"this is hello world"
			}
		})
	</script>
</body>

(2)双向数据绑定:使用v-model
下述代码实现的效果是,当input的value发生变化则div里的数据也会改变,当div的数据发生变化,input的value也会发生变化。

<body>
	<div id="root">
		<input v-model="content"/>
		<div>{{content}}</div>
	</div>
	<script>
		new Vue({
			el:"#root",
			data:{
				content:"this is content"
			}
		})
	</script>
</body>

实现效果如下:
双向数据绑定实现效果

4.1.5.计算属性和侦听器

(1)计算属性
计算属性是在vue实例的computed中定义的。例如下面这个代码,实现将姓和名拼接起来的效果。这里的fullNAME对应的是一个函数,返回值就是计算属性的结果。

<body>
	<div id="root">
		姓:<input v-model="firstName"/>
		名:<input v-model="lastName"/>
		<div>{{fullName}}</div>
	</div>
	<script>
		new Vue({
			el:"#root",
			data:{
				firstName:'',
				lastName:''
			},
			computed:{
				fullName:function(){
					return this.firstName+' '+this.lastName
				}
			}
		})
	</script>
</body>

实现效果:
计算属性的实现效果使用计算属性的好处是,只有依赖属性改变计算属性才会重新计算,依赖属性不改变时计算属性直接将缓存中的内容显示在页面上。
(2)侦听器
侦听器是通过vue实例中的watch属性来实现的。
下面这个代码实现的是,当fullName改变(即firstName或lastName改变)是,count加一,并实时显示出count的值。

<body>
	<div id="root">
		姓:<input v-model="firstName"/>
		名:<input v-model="lastName"/>
		<div>{{fullName}}</div>
		<div>{{count}}</div>
	</div>
	<script>
		new Vue({
			el:"#root",
			data:{
				firstName:'',
				lastName:'',
				count:0
			},
			computed:{
				fullName:function(){
					return this.firstName+' '+this.lastName
				}
			},
			watch:{
				fullName:function(){
					this.count++;
				}
			}
		})
	</script>
</body>

实现效果:
侦听器实现效果

4.1.6.v-if、v-show与v-for指令

v-if判断dom存在与否;v-show判断dom显示与否;v-for将列表循环展示。
下面这两个代码实现的都是点击button显示或者隐藏hello world。
使用v-if:

<body>
	<div id="root">
		<div v-if="show">hello world!</div>
		<button @click="handleClick">toggle</button>
	</div>
	<script>
		new Vue({
			el:"#root",
			data:{
				show:true
			},
			methods:{
				handleClick:function(){
					this.show=!this.show
				}
			}
		})
	</script>
</body>

使用v-show:

<body>
	<div id="root">
		<div v-show="show">hello world!</div>
		<button @click="handleClick">toggle</button>
	</div>
	<script>
		new Vue({
			el:"#root",
			data:{
				show:true
			},
			methods:{
				handleClick:function(){
					this.show=!this.show
				}
			}
		})
	</script>
</body>

这两个的区别在于,当使用v-if时,show为false时,直接删除这个div;使用v-show时,show为false则是隐藏这个div。因此,如果频繁的表示与非表示时,v-show性能优于v-if,相对应,安全性不高。
下面这个代码会显示以列表的形式显示list中的内容。

<body>
	<div id="root">
		<ul>
			<li v-for="(item,index) of list" :key="index">{{item}}</li>
		</ul>
	</div>
	<script>
		new Vue({
			el:"#root",
			data:{
				list:[1,2,3]
			}
		})
	</script>
</body>

使用v-for进行数据循环,通常每个元素要带上:key属性来提升页面元素渲染的性能。key属性要求值不能相同,上述的index表示的是元素在列表中的位置(即元素的下标),如果列表中的元素有重复的,使用index当key值是必要的,但是如果后续要对列表数据进行排序,使用index就会出现问题。

4.1.7.组件

这一块内容比较多,建议跟着慕课网学习。我将其中的代码粘在下面吧。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>TodoList</title>
	<script src="./vue.js"></script>
</head>
<body>
	<div id="root">
		<input v-model="inputValue" />
		<button @click="handleSubmit">提交</button>
		<ul>
			<todo-item
				v-for="(item,index) of list"
				:key="index"
				:content="item"
				:index="index"
				@delete="handleDelete"
			>
			</todo-item>
		</ul>
	</div>
	<script>
		/* 全局组件 */
		Vue.component('todo-item',{
			props:['content','index'],//接收父组件传来的数据
			template:'<li @click="handleClick">{{content}}</li>',
			methods:{
				handleClick:function(){
					this.$emit('delete',this.index)//向父组件传递数据
				}
			}
		})
		new Vue({
			el:"#root",
			data:{
				inputValue:'',
				list:[]
			},
			methods:{
				handleSubmit:function(){
					this.list.push(this.inputValue),//向列表list中增加一项
					this.inputValue=''//清空输入框
				},
				handleDelete:function(index){
					this.list.splice(index,1)//删除index位置的一个元素
				}
			}
		})
	</script>
</body>
</html>

组件=实例,两者其实是一样的。
慕课网的这一块其实讲的是很基础、很简单的,因此如果要进一步学习vue的相关知识,推荐到官网上学习。

4.2.vue.cli与vue的关系

Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供:

  • 通过 @vue/cli 实现的交互式的项目脚手架。(有没有和我一样不知道脚手架是什么意思的小可爱~)
  • 通过 @vue/cli + @vue/cli-service-global 实现的零配置原型开发。
  • 一个运行时依赖 (@vue/cli-service),该依赖:
    • 可升级;
    • 基于 webpack 构建,并带有合理的默认配置;
    • 可以通过项目内的配置文件进行配置;
    • 可以通过插件进行扩展。
  • 一个丰富的官方插件集合,集成了前端生态中最好的工具。
  • 一套完全图形化的创建和管理 Vue.js 项目的用户界面。

Vue CLI 致力于将 Vue 生态中的工具基础标准化。它确保了各种构建工具能够基于智能的默认配置即可平稳衔接,这样就可以专注在撰写应用上,而不必花好几天去纠结配置的问题。与此同时,它也为每个工具提供了调整配置的灵活性,无需 eject。

4.3.vue.cli的安装

参考官网https://cli.vuejs.org/zh/guide/installation.html
使用这两个命令都可以。但是,如你所见,要使用npm和yarn命令,必须先回到这篇文章的开始,安装好node.js和yarn。

npm install -g @vue/cli
# OR
yarn global add @vue/cli

安装完成后,可以使用vue --version命令检查是否安装成功(安装成功会显示版本号)。
vue.cli安装成功截图

5.使用vue.cli搭建一个基本项目

(不要选择默认,手动安装,明白每一个选项的意义)

5.1.使用vue init(vue-cli2.x的初始化方式)的步骤:

1、从命令行里进入到待搭建项目的保存位置
 step1

2、使用下述命令新建一个项目,其中,< template-name >是指模板名称,< project-name >是指项目名称。

vue init <template-name> <project-name>

例如,使用webpack模板新建一个名为myProject的项目:
step2

3、新建项目的过程,会有以下一些问题需要回答:

? Project name  输入项目名称,直接回车即可
? Project description 输入项目描述,直接回车即可
? Author 作者,直接回车即可
? Vue build 打包方式/构建模式,两个选项,Runtime+Compiler,Runtime-only,一般直接回车即可(即默认选择Runtime+Compiler)
? Install vue-router?  选择  Y 使用 vue-router,输入 N 不使用,推荐Y
? Use ESLint to lint your code? 代码规范,推荐 N
? Setup unit tests with Karma + Mocha? 单元测试,推荐 N
? Setup e2e tests with Nightwatch? E2E测试,推荐N
? Should we run `npm install` for you after the project has been created? (recommended)  选择用什么install依赖组件

在这里插入图片描述
注意:
项目名称不可以包含大写字母,否则会报错。
在这里插入图片描述4、安装完成会有下面的这个提示:
在这里插入图片描述5、先使用cd命令进入到项目的文件夹,然后使用下述命令运行项目:

cd my_project
yarn run dev

当得到如下结果时,运行正确。
在这里插入图片描述6、复制上述网址在浏览器中打开,则可以得到基础页面,说明项目新建成功。
在这里插入图片描述

5.2.使用vue create(vue-cli3.x的初始化方式)的步骤

1、从命令行里进入到待搭建项目的保存位置
 step1

2、使用下述命令新建一个项目,其中,< project-name >是指项目名称。

vue create <project-name>

例如,新建一个名为first_page的项目:
在这里插入图片描述
3、新建项目的过程,会有以下一些问题需要回答:

//选择是手动(manually)还是自动(default)
? Please pick a preset  

这里最好是根据自己的需要手动选择配置。
在这里插入图片描述

//选择配置,选择需要的选项即可。(注:空格键是选中与取消,A键是全选)
? Check the features needed for your project: 

建议初学者先选择这几个,从简单的入手。
选项

//选择启动项目的vue.js版本
? Choose a version of Vue.js that you want to start the project with 

由于3.0是刚出来的版本,许多功能还不太适用,这里选择的是2.0的版本。
在这里插入图片描述

//之前配置里选择了router选项,这里就需要选择是否使用history模式
? Use history mode for router? (Requires proper server setup for index fallback in production) 

目前常用的router就是history模式,因此这里输入Y就可以了。
在这里插入图片描述

//选择css预处理模式
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default)  

导师推荐的使用less模式,关于sass和less模式有什么区别,请参考这篇文章
在这里插入图片描述

//代码风格、格式校验
? Pick a linter / formatter config  

这里选择的是Prettier。
在这里插入图片描述

 //选择语法检查方式
? Pick additional lint features   

这里选择的是边编译边保存。
在这里插入图片描述

//自定义配置的存放位置
? Where do you prefer placing config for Babel, ESLint, etc.?   

这里最好单独弄个文件来保存这些配置,因此选择第一个选项。
在这里插入图片描述

//是否保存当前选择的配置项
? Save this as a preset for future projects? 

我感觉前面阶段大部分都是这个配置,因此这里选择了保存。也可以选择不保存,后面重新根据需要配置即可。
在这里插入图片描述

//存储当前配置项的名称
? Save preset as

这里自己命名即可,直接输入。
在这里插入图片描述

4、配置安装完成后会有下面的这个提示:
在这里插入图片描述
5、按照上面的提示,先使用cd first_page命令进入到项目的文件夹,然后使用yarn serve命令运行项目:

cd first_page
yarn serve

当得到如下结果时,运行正确。
在这里插入图片描述

6、复制上述网址在浏览器中打开,则可以得到基础页面,说明项目新建成功。
在这里插入图片描述
vue init 和vue create的区别请参考博客https://blog.youkuaiyun.com/sinat_29158831/article/details/103876945

5.3.项目目录结构

打开这个项目,查看生成的目录结构。
在这里插入图片描述文件夹:
build —— webpack相关配置文件,一般情况下不需要自己配置
config —— vue基本配置文件,可配置端口号,打包输出等
node_modules —— 依赖包,也就是运行cnpm install 安装的依赖组件都在这里
src —— 项目核心文件,自己写的代码基本都放在这里面
static —— 静态资源,一般图片类资源都放在这里

文件:
.babelrc —— babel编译参数(不清楚干啥用的)
.editorconfig —— 代码格式
.gitignore —— git上传需要忽略的文件配置
.postcssrc.js —— 转换css的工具
index.html —— 主页
package.json —— 项目基本信息及项目依赖关系
README.md —— 项目说明

5.4.参考链接

使用Vue-cli搭建项目与目录详解
使用vue-cli创建vue项目及项目结构说明
Vue学习笔记(二)——使用vue.cli3
vue-cli3.0-beta vue脚手架3.0的使用
超级详细的Vue-cli3使用教程

6.引入vue.router,iview

6.1.Vue Router

Vue Router是 Vue.js官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:

  • 嵌套的路由/视图表
  • 模块化的、基于组件的路由配置
  • 路由参数、查询、通配符
  • 基于 Vue.js 过渡系统的视图过渡效果
  • 细粒度的导航控制
  • 带有自动激活的 CSS class 的链接
  • HTML5 历史模式或 hash 模式,在 IE9 中自动降级
  • 自定义的滚动条行为

router的模式有两种:hash模式和history模式。两者的区别请参考这篇文章

6.2.iview / view ui

View UI,即原先的 iView,是一套基于 Vue.js 的开源 UI 组件库,主要服务于 PC 界面的中后台产品。其特性有:

  • 丰富的组件和功能,满足绝大部分网站场景
  • 提供开箱即用的 Admin 系统 和 高阶组件库,极大程度节省开发成本
  • 提供专业、优质的一对一技术支持
  • 友好的 API ,自由灵活地使用空间
  • 细致、漂亮的 UI
  • 事无巨细的文档
  • 可自定义主题

6.3.引入view ui

当前项目根目录执行命令

npm install iview --save
或
yarn add iview

在这里插入图片描述

6.4.引入vue-router

在上面的构建项目时,已经引入了router。

6.5.参考链接

vue - router + iView 的使用(简单例子)
view UI安装官网
Vue Router安装官网

7.还原一个简单页面

基本上第一周学习的就是以上这些基础内容,还原页面这一步,只能留在下一周了。
继续加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值