Vue详解

Vue详解

Vue.js目前最火的一个前端框架。点击跳转Vue详解视频

在这里插入图片描述

在谷底也要开花!

P00 前言:回顾SSM阶段

在这里插入图片描述

P01 前端核心分析

Vue:前端体系、前后端分离

1、概述

Vue(读音 /vju`/,类似于 view)是一套用于构建用户界面的渐进式框架,发布于2014年2月。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库(如:vue-router:跳转,vue-resource:通信,vuex:管理)或既有项目整合。

官网:https://cn.vuejs.org/v2/guide/

Soc:关注点分离原则

HTML + CSS + JS:视图:给用户看,刷新后台给的数据

网络通信:axios http://www.axios-js.com/

页面跳转:vue-router

状态管理:vuex

Vue-UI:ICE https://ice.work/

webpack

let --> var

var

css / 新技能

2、前端知识体系

想要成为真正的"互联网Java全栈工程师"还有很长的一段路要走,其中“我大前端”是绕不开的一门必修课。本阶段课程的主要目的就是带领我Java后台程序员认识前端、了解前端、掌握前端,为实现成为“互联网Java全栈工程师”再向前迈进一步。

2.1、前端三要素

  • HTML(结构):超文本标记语言(Hyper Text Markup Language),决定网页的结构和内容
  • CSS(表现):层叠样式表(Cascading Style Sheets),设定网页的表现样式
  • JavaScript(行为):是一种弱类型脚本语言,其源代码不需经过编译,而是由浏览器解释运行,用于控制网页的行为

2.2、结构层(HTML)

太简单,略

2.3、表现层(CSS)

CSS层叠样式表是一门标记语言,并不是编程语言,因此不可以自定义变量,不可以引用等,换句话说就是不具备任何语法支持,它主要缺陷如下:

  • 语法不够强大,比如无法嵌套书写,导致模块化开发中需要书写很多重复的选择器;
  • 没有变量和合理的样式复用机制,使得逻辑上相关的属性值必须以字面量的形式重复输出,导致难以维护;

这就导致了我们在工作中无端增加了许多工作量。为了解决这个问题,前端开发人员会使用一种称之为【CSS 预处理器】的工具,提供CSS缺失的样式层复用机制、减少冗余代码,提高样式代码的可维护性。大大提高了前端在样式上的开发效率。

什么是CSS预处理器

CSS预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为CSS增加了一些编程的特性,将CSS作为目标生成文件,然后开发者就只要使用这种语言进行CSS的编码工作。转化成通俗易懂的话来说就是“用一种专门的编程语言,进行Web页面样式设计,再通过编译器转化为正常的CSS文件,以供项目使用”。

常用的CSS预处理器有哪些

  • SASS:基于Ruby,通过服务端处理,功能强大。解析效率高。需要学习Ruby语言,上手难度高于LESS。
  • LESS:基于NodeJS,通过客户端处理,使用简单。功能比SASS简单,解析效率也低于SASS,但在实际开发中足够了,所以我们后台人员如果需要的话,建议使用LESS。

http://lesscss.cn/

2.4、行为层(JavaScript)

JavaScript一门弱类型脚本语言,其源代码在发往客户端运行之前不需经过编译,而是将文本格式的字符代码发送给浏览器由浏览器解释运行。

Native 原生 JS 开发

原生JS开发,也就是让我们按照【ECMAScript】标准的开发方式,简称是ES,特点是所有浏览器都支持。截止到当前博客发布时间,ES标准已发布如下版本:

  • ES3
  • ES4(内部,未正式发布)
  • ES5(全浏览器支持)
  • ES6(常用,当前主流版本:webpack打包成为ES5支持!)
  • ES7
  • ES8
  • ES9(草案阶段)

区别就是逐步增加新特性。

TypeScript 微软的标准

TypeScript是一种由微软开发的自由和开源的编程语言。它是JavaScript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。由安德斯.海尔斯伯格(C#、Delphi、TypeScript之父;.NET创立者)主导。

该语言的特点就是除了具备ES的特性之外还纳入了许多不在标准范围内的新特性,所以会导致很多浏览器不能直接支持TypeScript语法,需要编译后(编译成JS)才能被浏览器正确执行。

JavaScript 框架

  • jQuery:大家熟知的JavaScript框架,优点是简化了DOM操作,缺点是DOM操作太频繁,影响前端性能;在前端眼里使用它仅仅是为了兼容IE6、7、8;
  • Angular:Google收购的前端框架,由一群Java程序员开发,其特点是将后台的MVC模式搬到了前端并增加了模块化开发的理念,与微软合作,采用TypeScript语法开发;对后台程序员友好,对前端程序员不太友好;最大的缺点是版本迭代不合理(如:1代->2代,除了名字,基本就是两个东西;截止发表博客时已推出了Angular6)
  • React:Facebook出品,一款高性能的JS前端框架;特点是提出了新概念【虚拟DOM】用于减少真实DOM操作,在内存中模拟DOM操作,有效的提升了前端渲染效率;缺点是使用复杂,因为需要额外学习一门【JSX】语言;
  • Vue:一款渐进式JavaScript框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了Angular(模块化)和React(虚拟DOM)的优点;

M:模型 V:视图 C:控制器

View:JSP {{}}

DATA:数据
vm:数据双向绑定

虚拟Dom:利用内存;

计算属性–>Vue特色

集大成者:

MVVM + Dom

  • Axios:前端通信框架;因为Vue的边界很明确,就是为了处理DOM,所以并不具备通信能力,此时就需要额外使用一个通信框架与服务器交互;当然也可以直接选择使用jQuery提供的AJAX通信功能;

P02 前端发展史

UI 框架

  • Ant-Design:阿里巴巴出品,基于React的UI框架
  • ElementUI、iview、ice:饿了么出品、基于Vue的UI框架
  • Bootstrap:Twitter推出的一个用于前端开发的开源工具包
  • AmazeUI:又叫"妹子UI",一款HTML5跨屏前端框架 http://amazeui.shopxo.net/

JavaScript 构建工具

  • Babel:JS编译工具,主要用于浏览器不支持的ES新特性,比如用于编译TypeScript
  • WebPack:模块打包器,主要作用是打包、压缩、合并及按序加载

注:以上知识点已将WebAPP开发所需技能全部梳理完毕。

2.5、三端统一

混合开发(Hybird APP)

主要目的是实现一套代码三端统一(PC、Android:.apk、iOS:.ipa)并能够调用到设备底层硬件(如:传感器、GPS、摄像头等),打包方式主要有一下两种:

  • 云打包:HBuild -> HBuildX,DCloud出品;API Cloud
  • 本地打包:Cordova(前身是PhoneGap)

微信小程序

详见微信官网,这里就是介绍一个方便微信小程序UI开发的框架:WeUI

2.6、后端技术

前端人员为了方便开发也需要掌握一定的后端技术,但我们Java后台人员知道后台知识体系极其庞大复杂,所以为了方便前端人员开发后台应用,就出现了NodeJS这样的技术。

NodeJS的作者已经声称放弃NodeJS(说是架构做的不好再加上笨重的node_modules,可能让作者不爽了吧),开始开发全新架构的Deno

既然是后台技术,那肯定也需要框架和项目管理工具,NodeJS框架及项目管理工具如下:

  • Express:NodeJS框架
  • Koa:Express简化版
  • NPM:项目综合管理工具,类似于Maven
  • YARN:NPM的替代方案,类似于Maven和Gradle的关系

2.7、主流前端框架

Vue.js

iView

iview 是一个强大的基于Vue的UI库,有很多实用的基础组件比elementui的组件更丰富,主要服务于PC界面的中后台产品。使用单文件的Vue组件化开发模式基于 npm + webpack + babel 开发,支持ES2015 高质量、功能丰富 友好的API,自由灵活地使用空间。

  • 官网地址 https://www.iviewui.com/
  • Github https://github.com/view-design/ViewUI
  • iview-admin

备注:属于前端主流框架,选型时可考虑使用,主要特点是移动端支持较多

ElementUI

Element是饿了么前端开源维护的Vue UI组件库,组件齐全,基本涵盖后台所需的所有组件,文档讲解详细,例子也很丰富。主要用于开发PC端的页面,是一个质量比较高的Vue UI组件库。

  • 官网地址 https://element.eleme.cn/#/zh-CN
  • Github https://github.com/ElemeFE/element
  • vue-element-admin https://panjiachen.github.io/vue-element-admin-site/zh/

备注:属于前端主流框架,选型时可考虑使用,主要特点是桌面端支持较多

ICE

飞冰是阿里巴巴团队基于 React/Angular/Vue的中后台应用解决方案,在阿里巴巴内部,已经有270多个来自几乎所有BU的项目在使用。飞冰包含了一条从设计端到开发端的完整链路,帮助用户快速搭建属于自己的中后台应用。

  • 官网地址
  • Github

备注:主要组件还是以React为主,截止2019年02月17日更新博客前对Vue的支持还不太完善,目前尚处于观望阶段。

VantUI

Vant UI 是有赞前端团队基于有赞统一的规范实现的Vue组件库,提供了一整套UI基础组件和业务组件。通过Vant,可以快速搭建出风格统一的页面,提升开发效率。

  • 官网地址
  • Github

AtUI

at-ui是一款基于 Vue 2.x的前端UI组件库,主要用于快速开发PC网站产品。它提供了一套npm + webpack + babel 前端开发工作流程,CSS样式独立,即使采用不同的框架实现都能保持统一的UI风格。

  • 官网地址
  • Github

CubeUI

cube-ui 是滴滴团队开发的基于Vue.js实现的精致移动端组件库。支持按需引入和后编译,轻量灵活;扩展性强,可以方便地基于现有组件实现二次开发。

  • 官网地址
  • Github

混合开发

Flutter

Flutter 是谷歌的移动端UI框架,可在极短的时间内构建Android和iOS上高质量的原生级应用。Flutter可与现有代码一起工作,它被世界各地的开发者和组织使用,并且Flutter是免费和开源的。

  • 官网地址
  • Github

备注:Google出品,主要特点是快速构建原生APP应用程序,如做混合应用该框架为必选框架。

Ionic

Ionic即是一个CSS框架也是一个JavaScript UI库,Ionic是目前最有潜力的一款HTML5手机应用开发框架。通过SASS构建应用程序,它提供了很多UI组件来帮助开发者开发强大的应用。它使用JavaScript MVVM框架和AngularJS/Vue 来增强应用。提供数据的双向绑定,使用它成为Web和移动开发者的共同选择。

  • 官网地址
  • 官网文档
  • Github

微信小程序

mpvue

mpvue是美团开发的一个使用Vue.js开发小程序的前端框架,目前支持 微信小程序、百度智能小程序、头条小程序和支付宝小程序。框架基于Vue.js,修改了的运行时框架runtime和代码编译器compiler实现,使其可运行在小程序环境中,从而为小程序开发引入了Vue.js开发体验。

  • 官网地址
  • Github

备注:完备的Vue开发体验,并且支持多平台的小程序开发,推荐使用

WeUI

WeUI是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一。包含button、cell、dialog、toast、article、icon等各式元素。

  • 官网地址
  • Github

3、了解前后分离的演变史

为什么需要前后分离

3.1、后端为主的MVC时代

为了降低开发的复杂度,以后端为出发点,比如:Struts、SpringMVC等框架的使用,就是后端的MVC时代;

在这里插入图片描述

  • 发起请求到前端控制器(DispatcherServlet)
  • 前端控制器请求HandlerMapping查找Handler,可以根据xml配置、注解进行查找
  • 处理器映射器HandlerMapping向前端控制器返回Handler
  • 前端控制器调用处理器适配器去执行Handler
  • 处理器适配器去执行Handler
  • Handler执行完成给适配器返回ModelAndView
  • 处理器适配器向前端控制器返回ModelAndView,ModelAndView是SpringMVC框架的一个底层对象,包括Model和View
  • 前端控制器请求视图解析器去进行视图解析,根据逻辑视图名解析成真正的视图(JSP)
  • 视图解析器向前端控制器返回View
  • 前端控制器进行视图渲染,视图渲染将模型数据(在ModelAndView对象中)填充到request域
  • 前端控制器向用户相应结果

优点

MVC是一个非常好的协作模式,能够有效降低代码的耦合度,从架构上能够让开发者明白代码应该写在哪里。为了让View更纯粹,还可以使用Thymeleaf、Freemarker等模板引擎,使模板里无法写入Java代码,让前后端分工更加清晰。

缺点

  • 前端开发重度依赖开发环境,开发效率低,这种架构下,前后端协作有两种模式:
    • 第一种是前端写DEMO,写好后,让后端去套模板。好处是DEMO可以本地开发,很高效。不足是还需要后端套模板,有可能套错,套完后还需要前端确定,来回沟通调整的成本比较大;
    • 另一种协作模式是前端负责浏览器端的所有开发和服务器端的View层模板开发。好处是UI相关的代码都是前端去写好,后端不用太关注,不足就是前端开发重度绑定后端环境,环境成为影响前端开发效率的重要因素。
  • 前后端职责纠纷不清:模板引擎功能强大,依旧可以通过拿到的上下文变量来实现各种业务逻辑。这样,只要前端弱势一点,往往就会被后端要求在模板层写出不少业务代码。还有一个很大的灰色地带是Controller,页面路由等功能本应该是前端最关注的,但却是由后端来实现。Controller本身与Model往往也会纠缠不清,看了让人咬牙的业务代码经常会出现在Controller层。这些问题不能全归结于程序员的素养,否则JSP就够了。
  • 对前端发挥的局限性:性能优化如果只在前端做空间非常有限,于是我们经常需要后端合作,但由于后端框架限制,我们很难使用【Comet】、【BigPipe】等技术方案来优化性能。

注:在这期间(2005年以前),包括早期的JSP、PHP可以称之为Web1.0时代。在这里想说一句,如果你是一名Java初学者,请你不要再把一些陈旧的技术当回事了,比如JSP,因为时代在变、技术在变、什么都在变(引用扎克伯格的一句话:唯一不变的是变化本身);当我们去给大学做实训时,有些同学会认为我们没有讲什么干货,其实不然,只能说是你认知里的干货对于市场来说早就过时了而已。

3.2、基于AJAX带来的SPA时代

时间回到2005年AJAX(Asynchronous JavaScript And XML,异步JavaScript和XML,老技术新用法)被正式提出并开始使用CDN作为静态资源存储,于是出现了JavaScript王者归来(在这之前JS都是用来在网页上贴狗皮膏药广告的)的SPA(Single Page Application)单页面应用时代。

在这里插入图片描述

优点

这种模式下,前后端的分工非常清晰,前后端的关键协作点是AJAX接口。看起来是如此美妙,但回过头来看看的话,这与JSP时代区别不大。复杂度从服务端的JSP里已到了浏览器的JavaScript,浏览器端变得很复杂。类似Spring MVC,这个时代开始出现浏览器端的分层架构

在这里插入图片描述

缺点

  • 前后端接口的约定:如果后端的接口一塌糊涂,如果后端的业务模型不够稳定,那么前端开发会很痛苦;不少团队也有类似尝试,通过接口规则、接口平台等方式来做。有了和后端一起沉淀的接口规则,还可以用来模拟数据,使得前后端可以在约定接口后实现高效并行开发
  • 前端开发的复杂度控制:SPA应用大多以功能交互型为主,JavaScript代码过十万行很正常。大量JS代码的组织,与View层的绑定等,都不是容易的事情。

3.3、前端为主的MV*时代

大前端时代:后端:轻松、分布式、微服务、大数据

裁员:好事

1 1.8 3

此处的MV*模式如下:

  • MVC(同步通信为主):Model、View、Controller
  • MVP(异步通信为主):Model、View、Presenter
  • MVVM(异步通信为主):Model、View、ViewModel

为了降低前端开发复杂度,涌现了大量的前端框架,比如:AngularJS、React、Vue.js、EmberJS等,这些框架总的原则是先按类型分层,比如Templates、Controllers、Models,然后再在层内做切分,如下图:

在这里插入图片描述

优点

  • 前后端职责很清晰:前端工作在浏览器端,后端工作在服务端。清晰的分工,可以让开发并行,测试数据的模拟不难,前端可以本地开发。后端则可以专注于业务逻辑的处理,输出RESTful等接口。
  • 前端开发的复杂度可控:前端代码很重,但合理的分层,让前端代码能各司其职。这一块蛮有意思的,简单如模板特性的选择,就有很多很多讲究。并非越强大越好,限制什么,留下哪些自由,代码应该如何组织,所有这一切设计,得花一本书的厚度去说明。
  • 部署相对独立:可以快速改进产品体验

缺点

  • 代码不能复用。比如后端依旧需要对数据做各种校验,校验逻辑无法复用浏览器端的代码。如果可以复用,那么后端的数据校验可以相对简单化。
  • 全异步,对SEO不利。往往还需要服务端做同步渲染的降级方案。
  • 性能并非最佳,特别是移动互联网环境下。
  • SPA不能满足所有需求,依旧存在大量多页面应用。URL Design需要后端配合,前端无法完全掌控。

3.4、NodeJS带来的全栈时代

前端为主的MV*模式解决了很多很多问题,但如上所述,依旧存在不少不足之处。随着NodeJS的兴起,JavaScript开始有能力运行在服务端。这意味着可以有一种新的研发模式:

在这里插入图片描述

在这种研发模式下,前后端的职责很清晰。对前端来说,两个UI层各司其职:

  • Front-end UI layer 处理浏览器层的展现逻辑。通过CSS渲染样式,通过JavaScript添加交互功能,HTML的生成也可以放在这层,具体看应用场景。
  • Back-end UI layer 处理路由、模板、数据获取、Cookie等。通过路由,前端终于可以自主把控URL Design,这样无论是单页面应用还是多页面应用,前端都可以自由调控。后端也终于可以摆脱对展现的强关注,转而可以专心于业务逻辑层的开发。

通过Node,Web Server层也是JavaScript代码,这意味着部分代码可前后复用,需要SEO的场景可以在服务端同步渲染,由于异步请求太多导致的性能问题也可以通过服务端来缓解。前一种模式的不足,通过这种模式几乎都能完美解决掉。

与JSP模式相比,全栈模式看起来是一种回归,也的确是一种向原始开发模式的回归,不过是一种螺旋上升的回归。

基于NodeJS的全栈模式,依旧面临很多挑战:

  • 需要前端对服务端编程有更进一步的认识。比如TCP/IP等网络知识的掌握。
  • NodeJS层与Java层的高效通信。NodeJS模式下,都在服务器端,RESTful HTTP通信未必高效,通过SOAP等方式通信更高效。一切需要在验证中前行。
  • 对部署、运维层面的熟练了解,需要更多知识点和实操经验。
  • 大量历史遗留问题如何过渡。这可能是最大的阻力。

注:看到这里,相信很多同学就可以理解,为什么我总在课堂上说:“前端想学后台很难,而我们后端程序员学任何东西都很简单”;就是因为我们后端程序员具备相对完善的知识体系。

全栈!So Easy!笑~!

3.5、总结

综上所述,模式也好,技术也罢,没有好坏优劣之分,只有适合不适合;前后分离的开发思想主要是基于SoC(关注度分离原则),上面种种模式,都是让前后端的职责更清晰,分工更合理高效。

P03 第一个 Vue 程序

什么是MVVM

MVVM(Model-View-ViewModel)是一种软件架构设计模式,由微软WPF(用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight(类似于Java Applet,简单点说就是浏览器上运行的WPF)的架构师Ken Cooper 和 Ted Peters 开发,是一种简化用户界面的事件驱动编程方式。由John Gossman(同样也是WPF和Silverlight的架构师)于2005年在他的博客上发表。

MVVM源自于经典的MVC(Model-View-Controller)模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用,其作用如下:

  • 该层向上与视图层进行双向数据绑定
  • 向下与Model层通过接口请求进行数据交互

在这里插入图片描述

MVVM已经相当成熟了,主要运用但不仅仅在网络应用程序开发中。当下流行的MVVM框架有Vue.js,Angular.js等。

为什么要使用MVVM

MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处

  • 低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
  • 可复用:你可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。
  • 独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
  • 可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。

MVVM的组成部分

在这里插入图片描述

Vue

Vue(读音 /vju`/,类似于 view)是一套用于构建用户界面的渐进式框架,发布于2014年2月。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库(如:vue-router:跳转,vue-resource:通信,vuex:管理)或既有项目整合。

官网:https://cn.vuejs.org/v2/guide/

MVVM模式的实现者

  • Model:模型层,在这里表示JavaScript对象
  • View:视图层,在这里表示DOM(HTML操作的元素)
  • ViewModel:连接视图和数据的中间件,Vue.js就是MVVM中的ViewModel层的实现者

在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个Observer观察者

  • ViewModel能够观察到数据的变化,并对视图对应的内容进行更新
  • ViewModel能够监听到视图的变化,并能够通知数据发生改变

至此,我们就明白了,Vue.js就是一个MVVM的实现者,他的核心就是实现了DOM监听与数据绑定

为什么要使用Vue.js

  • 轻量级,体积小是一个重要指标。Vue.js压缩后有只有20多kb(Angular 压缩后56kb+ React 压缩后 44kb+)
  • 移动优先。更适合移动端,比如移动端的Touch事件
  • 易上手,学习曲线平稳,文档齐全
  • 吸取了Angular(模块化)和React(虚拟DOM)的长处,并拥有自己独特的功能,如:计算属性
  • 开源,社区活跃度高
  • … …

Vscode

Hubilder

Sublime

WebStrom

第一个Vue程序

【说明】IDEA可以安装Vue插件!

注意:Vue不支持IE8及一下版本,因为Vue使用了IE8无法模拟的ECMAScript5特性。但它支持所有兼容ECMAScript5的浏览器。

下载地址

  • 开发版本

    • 包含完整的警告和调试模式:https://vuejs.org/js/vue.js
    • 删除了警告,30.96KB min + gzip:https://vuejs.org/js/vue.min.js
  • CDN

demo1.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>

<h1>牛魔瘦了</h1>

<!--view层 模板-->
<div id="app">
    {{message}}
</div>

<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        //Model:数据
        data:{
            message:"hello,vue!"
        }
    });
</script>

</body>
</html>

P04 Vue 基本语法

v-bind

demo1.html

<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>牛魔瘦了</h1>

<!--view层 模板-->
<div id="app">
    <span v-bind:title="message">
        鼠标悬停几秒种查看此处动态绑定的提示信息!
    </span>
</div>

<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        //Model:数据
        data:{
            message:"hello,vue!"
        }
    });
</script>

</body>
</html>

v-if,v-else,v-else-if

demo2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--view层 模板-->
<div id="app">

    <h1 v-if="ok">Yes</h1>
    <h1 v-else>No</h1>

    <h1 v-if="type==='A'">A</h1>
    <h1 v-else-if="type==='B'">B</h1>
    <h1 v-else-if="type==='D'">D</h1>
    <h1 v-else>C</h1>

</div>

<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        //Model:数据
        data:{
            ok: true,
            type: 'A'
        }
    });
</script>

</body>
</html>

v-for

demo3.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--view层 模板-->
<div id="app">

    <li v-for="(item, index) in items">
        {{item.message}}--{{index}}
    </li>

</div>

<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        //Model:数据
        data:{
            items: [
                {message: '牛魔说Java'},
                {message: '牛魔说前端'},
                {message: '牛魔说运维'}
            ]
        }
    });
</script>

</body>
</html>

P05 Vue 绑定事件

jQuery事件:https://www.runoob.com/jquery/jquery-events.html

demo4.html

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--view层 模板-->
<div id="app">
    <button v-on:click="sayHi">click me</button>
</div>

<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            message: "牛魔说Java"
        },
        methods: { //方法必须定义在 Vue 的 Methods对象中,v-on: 事件
            sayHi: function(event){
                alert(this.message);
            }
        }
    });
</script>

</body>
</html>

P06 Vue 双向绑定

demo5.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--view层 模板-->
<div id="app">

    <p>输入的文本:<input type="text" v-model="message"> {{message}}</p>

    <p><textarea name="" id="" cols="30" rows="10" v-model="message2"></textarea> {{message2}}</p>

    <p>
        性别:
        <input type="radio" name="sex" value="" v-model="niumo"/><input type="radio" name="sex" value="" v-model="niumo"/><p>选中了谁:{{niumo}}</p>
    </p>

    <p>
        <input type="checkbox" id="xj" value="香蕉" v-model="checkedNames">
        <label for="xj">香蕉</label>
        <input type="checkbox" id="pg" value="苹果" v-model="checkedNames">
        <label for="pg">苹果</label>
        <input type="checkbox" id="xg" value="西瓜" v-model="checkedNames">
        <label for="xg">西瓜</label>
        <input type="checkbox" id="mg" value="芒果" v-model="checkedNames">
        <label for="mg">芒果</label>
        <input type="checkbox" id="pp" value="琵琶" v-model="checkedNames">
        <label for="pp">琵琶</label>
        <input type="checkbox" id="pt" value="葡萄" v-model="checkedNames">
        <label for="pt">葡萄</label>
        <br>
        <span>Checked names: {{ checkedNames }}</span>
    </p>

    <p>
        下拉框
        <select v-model="selected">
            <option value="" disabled>--请选择--</option>
            <option>A</option>
            <option>B</option>
            <option>C</option>
        </select>
        <span>value:{{selected}}</span>
    </p>

</div>

<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            message: "牛魔瘦了",
            message2: "孙悟空",
            niumo: "女",
            selected: "A",
            checkedNames: ["西瓜","葡萄"]
        }
    });
</script>

</body>
</html>

P07 Vue 组件讲解

通常一个应用会以一棵嵌套的组件树的形式来组织:

在这里插入图片描述

例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。

demo6.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--view层 模板-->
<div id="app">

    <niumo v-for="item in items" v-bind:niu="item"></niumo>

</div>

<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>

    //定义一个Vue组件component
    Vue.component("niumo",{
        props: ['niu'],
        template: '<li>{{niu}}</li>'
    });

    var vm = new Vue({
        el: "#app",
        data: {
            items: ["Java","Linux","前端"]
        }
    });
</script>

</body>
</html>

P08 Axios 异步通信

GitHub:https://github.com/axios/axios

中文文档:http://www.axios-js.com/

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

data.json

{
  "name": "牛魔瘦了",
  "url": "http://www.axios-js.com/",
  "page": 1,
  "isNonProfit": true,
  "address": {
    "street": "天府五街",
    "city": "四川成都",
    "country": "中国"
  },
  "links": [
    {
      "name": "bilibili",
      "url": "https://space.bilibili.com/"
    },
    {
      "name": "牛魔瘦了",
      "url": "https://www.niumo.com/"
    },
    {
      "name": "百度",
      "url": "https://www.baidu.com/"
    }
  ]
}

demo7.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <!--v-clock:解决闪烁问题-->
    <style>
        [v-clock]{
            display: none;
        }
    </style>

</head>
<body>

<div id="vue" v-clock>
    <div>{{info.name}}</div>
    <div>{{info.address.street}}</div>

    <a v-bind:href="info.url">点我</a>
</div>

<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
    var vm = new Vue({
        el: "#vue",

        //data: 属性: vm
        data(){
            return{
                // 请求的返回参数格式,必须和json字符串一样
                info:{
                    name: null,
                    address: {
                        street: null,
                        city: null,
                        country: null
                    },
                    url: null
                }
            }
        },
        mounted(){ //钩子函数 链式编程 ES6新特性
            axios.get('data.json').then(response=>(this.info=response.data));
        }
    });
</script>

</body>
</html>

P09 计算属性

计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销。

demo8.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--view层 模板-->
<div id="app">

    <p>currentTime1:{{currentTime1()}}</p>
    <p>currentTime2:{{currentTime2}}</p>

</div>

<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
    var vm = new Vue({
        el:" #app",
        data: {
            message: "hello,牛魔瘦了"
        },
        methods: {
            currentTime1: function(){
                return Date.now(); //返回一个时间戳
            }
        },
        computed: { //计算属性:methods,computed 方法名不能重名,重名之后,只会调用methods的方法
            currentTime2: function () {
                return Date.now(); //返回一个时间戳
            }
        }
    });
</script>

</body>
</html>

P10 插槽slot

demo9.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--view层 模板-->
<div id="app">
    <todo>
        <todo-title slot="todo-title" :title="title"></todo-title>
        <todo-items slot="todo-items" v-for="item in todoItems" :item="item"></todo-items>
    </todo>

</div>

<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>

    //slot:插槽
    Vue.component("todo",{
        template:
            '<div>\
                <slot name="todo-title"></slot>\
                <ul>\
                    <slot name="todo-items"></slot>\
                </ul>\
             </div>'
    });

    Vue.component("todo-title",{
        props: ['title'],
        template: '<div>{{title}}</div>'
    });

    Vue.component("todo-items",{
        props: ['item'],
        template: '<li>{{item}}</li>'
    });

    var vm = new Vue({
        el:" #app",
        data: {
            title: "牛魔老师系列课程",
            todoItems: ['牛魔说Java','牛魔说前端','牛魔说Linux']
        }

    });
</script>

</body>
</html>

P11 自定义事件内容分发

在这里插入图片描述

demo9.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--view层 模板-->
<div id="app">
    <todo>
        <todo-title slot="todo-title" :title="title"></todo-title>
        <todo-items slot="todo-items" v-for="(item,index) in todoItems"
                    :item="item" v-bind:index="index" v-on:remove="removeItems(index)" :key="index"></todo-items>
    </todo>

</div>

<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>

    //slot:插槽
    Vue.component("todo",{
        template:
            '<div>\
                <slot name="todo-title"></slot>\
                <ul>\
                    <slot name="todo-items"></slot>\
                </ul>\
             </div>'
    });

    Vue.component("todo-title",{
        props: ['title'],
        template: '<div>{{title}}</div>'
    });

    Vue.component("todo-items",{
        props: ['item','index'],
        //只能绑定当前组件的方法
        template: '<li>{{index}}---{{item}} <button @click="remove">删除</button></li>',
        methods: {
            remove: function (index) {
                // this.$emit 自定义事件分发
                this.$emit('remove',index);
            }
        }
    });

    var vm = new Vue({
        el:" #app",
        data: {
            title: "牛魔老师系列课程",
            todoItems: ['牛魔说Java','牛魔说前端','牛魔说Linux']
        },
        methods: {
            removeItems: function (index) {
                console.log("删除了"+this.todoItems[index]+"OK");
                this.todoItems.splice(index,1); //一次删除一个元素
            }
        }
    });
</script>

</body>
</html>

基础语法

条件判断 if for

网络通信:axios

组件以及界面布局

Vue单页面应用

Vue入门小结

核心:数据驱动,组件化

优点:借鉴了AngulaJS的模块化开发和React的虚拟Dom,虚拟Dom就是把Dom操作放到内存中执行;

常见的属性:

  • v-if
  • v-else-if
  • v-else
  • v-for
  • v-on 绑定事件,简写@
  • v-model 数据双向绑定
  • v-bind 给组件绑定参数,简写:

组件化:

  • 组合组件slot插槽
  • 组件内部绑定事件需要使用到this.$emit(“事件名”,“参数”);
  • 计算属性的特色,缓存计算数据

遵循SoC关注度分离原则,Vue是纯粹的视图框架,并不包含,比如Ajax之类的通信功能,为了解决通信问题,我们需要使用Axios框架做异步通信;

说明

Vue的开发都是要基于NodeJS,实际开发采用vue-cli脚手架开发,vue-router路由,vuex做状态管理;Vue UI,界面我们一般使用ElementUI(饿了么出品),或者ICE(阿里巴巴出品!)来快速搭建前端项目~

官网:

  • https://element.eleme.cn/#/zh-CN
  • https://ice.work/

P12 第一个 vue-cli 程序

安装vue-cli

cnpm install vue-cli -g
# 测试是否安装成功
# 查看可以基于哪些模板创建vue应用程序,通常我们选择webpack
vue list

在这里插入图片描述

在这里插入图片描述

第一个vue-cli应用程序

cd D:\chaochao\work\projects\study\vue
vue init webpack myvue

在这里插入图片描述

cd myvue
npm install
npm run dev

在这里插入图片描述

IDEA打开

在这里插入图片描述

P13 webpack学习使用

npm install webpack -g
npm install webpack-cli -g
# 测试安装成功:
webpack -v
webpack-cli -v

在这里插入图片描述

使用webpack

  • hello.js
//暴露一个方法
exports.sayHi = function () {
    document.write("<h1>牛魔说ES6</h1>");
}
exports.sayHi1 = function () {
    document.write("<h1>牛魔说ES6</h1>");
}
exports.sayHi2 = function () {
    document.write("<h1>牛魔说ES6</h1>");
}
exports.sayHi3 = function () {
    document.write("<h1>牛魔说ES6</h1>");
}
  • main.js
var hello = require("./hello");
hello.sayHi3();
  • webpack.config.js
module.exports = {
    entry: './modules/main.js',
    output: {
        filename: "./js/bundle.js"
    }
}
  • webpack

在这里插入图片描述

  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--前端的模块化开发-->
<script src="dist/js/bundle.js"></script>

</body>
</html>
  • 运行结果

在这里插入图片描述

  • webpack --watch (随时监听打包)

P14 vue-router路由

npm install vue-router --save-dev

# 如果上面命令安装失败,使用下面命令
npm install --legacy-peer-deps vue-router@3.5.2

在这里插入图片描述

  • ./router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'

import Content from '../components/Content'
import Main from '../components/Main'
import Niumo from '../components/niumo'

//安装路由
Vue.use(VueRouter);

//配置导出路由
export default new VueRouter({
  routes: [
    {
      //路由路径
      path: '/content',
      name: 'content',
      //跳转的组件
      component: Content
    },
    {
      //路由路径
      path: '/main',
      name: 'main',
      //跳转的组件
      component: Main
    },
    {
      //路由路径
      path: '/niumo',
      name: 'niumo',
      //跳转的组件
      component: Niumo
    }
  ]
});
  • ./components/Content.vue
<template>
  <h1>内容页</h1>
</template>

<script>
    export default {
        name: "Content"
    }
</script>

<style scoped>

</style>
  • ./components/Main.vue
<template>
  <h1>首页</h1>
</template>

<script>
    export default {
        name: "Main"
    }
</script>

<style scoped>

</style>
  • ./components/Niumo.vue
<template>
    <h1>niumo</h1>
</template>

<script>
    export default {
        name: "niumo"
    }
</script>

<style scoped>

</style>
  • main.js
import Vue from 'vue'
import App from './App'
import router from './router' //自动扫描里面的路由配置

Vue.config.productionTip = false

new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})
  • App.vue
<template>
  <div id="app">
    <h1>Vue-Router</h1>
    <router-link to="/main">首页</router-link>
    <router-link to="/content">内容页</router-link>
    <router-link to="/niumo">niumo</router-link>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
  • 运行结果

在这里插入图片描述

P15 vue+elementUI

https://element.eleme.cn/#/zh-CN

https://docsify.js.org/

# 初始化工程
vue init webpack hello-vue

# 进入工程目录
cd hello-vue

# 安装依赖
npm install

# 安装 vue-router
npm install --legacy-peer-deps vue-router@3.5.2

# 安装 element-ui
npm i element-ui -S

# 安装 SASS 加载器
cnpm install sass-loader node-sass --save-dev
# "sass-loader": "^4.0.0"

# 安装axios vue-axios
# axios官网:http://www.axios-js.com/
cnpm install --save axios vue-axios

# 启动测试
npm run dev

P16 路由嵌套

P17 参数传递及重定向

P18 404和路由钩子

  • /src/main.js
import Vue from 'vue'
import App from './App'

import router from './router'

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.use(VueAxios, axios)

Vue.use(router);
Vue.use(ElementUI);

Vue.config.productionTip = false

new Vue({
  el: '#app',
  router,
  render: h => h(App) //ElementUI
})
  • /src/App.vue
<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>
  • /src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'

import Main from '../views/Main'
import Login from '../views/Login'

import UserList from '../views/user/List'
import UserProfile from '../views/user/Profile'
import NotFound from "../views/NotFound"

Vue.use(Router);

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/main/:name',
      component: Main, //嵌套路由
      props: true,
      children: [
        //:id
        {path: '/user/profile/:id', name: 'UserProfile', component: UserProfile, props: true},
        {path: '/user/list',component:UserList},
      ]
    },
    {
      path: '/login',
      component: Login
    },
    {
      path: '/goHome',
      redirect: '/main'
    },
    {
      path: '/goLogin',
      redirect: '/login'
    },
    {
      path: '*',
      component: NotFound
    }
  ]
});
  • /src/views/Login.vue
<template>
  <div>
    <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
      <h3 class="login-title">欢迎登录</h3>
      <el-form-item label="账号" prop="username">
        <el-input type="text" placeholder="请输入账号" v-model="form.username"/>
      </el-form-item>
      <el-form-item label="密码" prop="password">
        <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" v-on:click="onSubmit('loginForm')">登录</el-button>
      </el-form-item>
    </el-form>

    <el-dialog
      title="温馨提示"
      :visible.sync="dialogVisible"
      width="30%"
      :before-close="handleClose">
      <span>请输入账号和密码</span>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
    export default {
        name: "Login",
        data() {
          return {
            form: {
              username: '',
              password: ''
            },
            //表单验证,需要在el-form-item 元素中增加prop 属性
            rules: {
              username: [
                {required: true, message: " 账号不可为空", trigger: 'blur'}
              ],
              password: [
                {required: true, message: " 密码不可为空 ", trigger: 'blur'}
              ]
            },
            //对话框显示和隐藏
            dialogVisible: false
          }
        },
        methods: {
          onSubmit(formName) {
            //为表单绑定验证功能
            this.$refs[formName].validate((valid) => {
              if (valid) {
                //使用vue-router路由到指定页面,该方式称之为编程式导航
                this.$router.push("/main/"+this.form.username);
              } else {
                this.dialogVisible = true;
                return false;
              }
            });
          }
        }
    }
</script>

<style lang="scss" scoped>
  .login-box {
    border: 1px solid #DCDFE6;
    width: 350px;
    margin: 180px auto;
    padding: 35px 35px 15px 35px;
    border-radius: 5px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    box-shadow: 0 0 25px #909399;
  }

  .login-title {
    text-align: center;
    margin: 0 auto 40px auto;
    color: #303133;
  }
</style>
  • /src/views/Main.vue
<template>
  <div>
    <el-container>
      <el-aside width="200px">
        <el-menu :default-openeds="['1']">
          <el-submenu index="1">
            <template slot="title"><i class="el-icon-caret-right"></i>用户管理</template>
            <el-menu-item-group>
              <el-menu-item index="1-1">
                <!--name-传组件名 params传递参数-->
                <router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</router-link>
              </el-menu-item>
              <el-menu-item index="1-2">
                <router-link to="/user/list">用户列表</router-link>
              </el-menu-item>
              <el-menu-item index="1-3">
                <router-link to="/goHome">回到首页</router-link>
              </el-menu-item>
            </el-menu-item-group>
          </el-submenu>

          <el-submenu index="2">
            <template slot="title"><i class="el-icon-caret-right"></i>内容管理</template>
            <el-menu-item-group>
              <el-menu-item index="2-1">分类管理</el-menu-item>
              <el-menu-item index="2-2">内容列表</el-menu-item>
            </el-menu-item-group>
          </el-submenu>

          <el-submenu index="3">
            <template slot="title"><i class="el-icon-caret-right"></i>系统管理</template>
            <el-menu-item-group>
              <el-menu-item index="3-1">用户设置</el-menu-item>
            </el-menu-item-group>
          </el-submenu>

        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="text-align: right; font-size: 12px;">
          <el-dropdown>
            <i class="el-icon-setting" style="margin-right: 15px;"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>
                <router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</router-link>
              </el-dropdown-item>
              <el-dropdown-item>
                <router-link to="/goLogin">退出登陆</router-link>
              </el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
          <span>{{name}}</span>
        </el-header>

        <el-main>
          <router-view/>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

<script>
    export default {
        props: ['name'],
        name: "Main"
    }
</script>

<style lang="scss" scoped>
  .el-header{
    background-color: lightblue;
    color: #333;
    line-height: 60px;
  }
  .el-aside{
    color: #333;
  }
</style>
  • /src/views/NotFound.vue
<template>
    <div>
      <h1>404,你的页面走丢了</h1>
    </div>
</template>

<script>
    export default {
        name: "NotFound"
    }
</script>

<style scoped>

</style>
  • /src/views/user/Profile.vue
<template>
  <!--所有的元素,必须不能直接在根节点下-->
  <div>
    <h1>个人信息</h1>
    {{id}}
  </div>
</template>

<script>
    export default {
        props: ['id'],
        name: "UserProfile",
        beforeRouteEnter: (to,from,next)=>{
          console.log("进入路由之前");
          next(vm => {
            vm.getData(); //进入路由之前执行getData;
          });
        },
        beforeRouteLeave: (to,from,next)=>{
          console.log("进入路由之后");
          next();
        },
        methods: {
          getData: function(){
            this.axios({
              method: 'get',
              url: 'http://localhost:8080/static/mock/data.json'
              }).then(function (response) {
                console.log(response);
            })
          }
        }
    }
</script>

<style scoped>

</style>
  • /static/mock/data.json
{
  "name": "牛魔瘦了",
  "url": "http://www.axios-js.com/",
  "page": 1,
  "isNonProfit": true,
  "address": {
    "street": "天府五街",
    "city": "四川成都",
    "country": "中国"
  },
  "links": [
    {
      "name": "bilibili",
      "url": "https://space.bilibili.com/"
    },
    {
      "name": "牛魔瘦了",
      "url": "https://www.niumo.com/"
    },
    {
      "name": "百度",
      "url": "https://www.baidu.com/"
    }
  ]
}
  • /src/views/user/List.vue
<template>
    <h1>用户列表</h1>
</template>

<script>
    export default {
        name: "UserList"
    }
</script>

<style scoped>

</style>
  • package.json
"sass-loader": "^4.0.0",
  • 18
    点赞
  • 116
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值