Vue(读音 /vjuː/,相似于 view),做者尤雨溪,是一套用于构建用户界面的渐进式框架。与其它大型框架不一样的是,Vue 被设计为能够自底向上逐层应用。Vue 的核心库只关注视图层,不只易于上手,还便于与第三方库(如:vue-rounter:跳转
,vue-resource:通讯
,vuex:管理
)或既有项目整合。另外一方面,当与现代化的工具链以及各类支持类库结合使用时,Vue也彻底可以为复杂的单页应用提供驱动。javascript
官网:https://cn.vuejs.org/css
想要成为真正的“互联网 Java 全栈工程师” 还有很长的一段路要走,其中“我大前端” 是绕不开的一门必修课。Java 程序员认识前端、了解前端、掌握前端,为实现成为“互联网 Java 全栈工程师” 再向前迈进一步。html
将前端页面比做一栋房子前端
HTML 是用来描述网页的一种语言,使用标签来描述网页。vue
标记标签一般被称为 HTML 标签,java
<html>
HTML 文档描述网页,包含 HTML 标签和纯文本。HTML 文档也称为网页node
CSS 层叠样式表是一门标记语言,并非编程语言,所以不能够自定义变量,不能够引用等,不具有任何语法支持。python
优势:jquery
缺点:webpack
这就致使了咱们在工做中增长了许多工做量。
为了解决这个问题,前端开发人员会使用一种称之为【CSS 预处理器】的工具,提供CSS 确实的样式层复用机制、减小冗余代码,提升样式代码的可维护性。大大提升了前端在样式上的开发效率。
什么是 CSS 预处理器?
CSS 预处理器定义了一种新的语言。其基本思想是:用一种专门的编程语言,为 CSS 增长一些编程的特性,将 CSS 做为目表生成文件,而后开发者就只要使用这种语言进行 CSS 的编码工做。也就是说“用一种专门的编程语言,进行 Web 页面样式设计。再经过编译器转化为正常的 CSS 文件,以供项目使用”
经常使用的 CSS预处理器:
JavaScript 是一门弱类型语言,其源代码在发往客户端运行以前不需通过编译,而是将文本格式的字符代码发送给浏览器,由浏览器解释运行。
原生 JavaScript 开发
原生 JavaScript 开发,也就是让咱们按照【ECMAScript】 标准的开发方式,简称 ES,特色是全部浏览器都支持。
ES 标准已发布以下版本:
区别就是逐步增长新特性。
TypeScript 微软的标准
TypeScipt 是一种由微软开发的自由和开源的编程语言。它是 JavaScript 的一个超集,并且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。由安德斯-海尔斯伯格(C#、Delphi、TypeScrpt之父:.NET 创立者)主导。
该语言的特色就是除了具有 ES 的特性以外,还归入许多不在标准范围内的新特性,因此会致使不少浏览器不能支持 TypeScript 语法,须要编译后(编译成 JS)才能被浏览器正确执行。
主要目的是实现一套代码三端统一(PC、Android:.apk、IOS:.ipa),并可以调用到设备底层硬件(如:传感器、GPS、摄像头等),打包方式主要由如下两种:
详见微信官网,这里就是介绍一个方便微信小程序 UI 开发的框架:WeUI
前端人员为了方便开发也须要掌握必定的后端技术,但咱们 Java 后台人员知道后台知识体系极其庞大复杂,因此为了方便前端人员开发后台应用,就出现了 NodeJS 这样的技术。
NodeJS 的做者已经声称放弃 NodeJS (说是架构作得很差再加上笨重的 node_modules,可能让做者爽了吧),开始开发全新架构的 Deno (于2020年5月13日发布1.0版本)
既然是后台技术,那确定也须要框架和项目管理工具,NodeJS 框架及项目管理工具以下:
iView 是一个强大的基于 Vue 的 UI 库,由不少使用的基础组件,比 Element UI 的组件更丰富,主要服务于 PC 界面的中后台产品。使用单文件的 Vue 组件化开发模式,基于 npm + webpack + babel 开发,支持 ES2015 高质量、功能丰富、友好的 API,自由灵活地使用空间
特色:移动端支持较多
Element UI 是饿了么前端开源维护的 Vue UI 组件库,组件齐全,基本涵盖后台所需的全部组件,文档讲解详细,例子也很丰富。主要用于开发 PC 端的页面,是一个质量比较高的 Vue UI 组件库。
GitHub:https://github.com/elemefe
vue-element-admin:https://panjiachen.github.io/vue-element-admin
特色:桌面端支持较多
飞冰是阿里巴巴团队基于 React/Angular/Vue 的中后台应用解决方案。在阿里巴巴内部,已经由270 多个来自几乎全部 BU 的项目在使用。飞冰包含了一条从设计段到开发段的完整链路,帮助用户快速搭建属于本身的中后台应用。
特色:主要组件仍是以 React 为主,目前对 Vue 的支持还不太完善,目前尚处于官网阶段。
Vant UI 是有赞前端团队基于有赞统一的规范实现的 Vue 组件库,提供了一整套 UI 基础组件和业务组件。经过 Vant ,能够快速搭建出风格统一的页面,提高开发效率。
at-ui 是一款基于 Vue 2.x 的前端 UI 组件库,主要用于快速开发 PC 网站产品,它提供了一套 npm + webpack + bable 前端开发工做流程,CSS 样式独立,即便采用不一样的框架实现都能保持统一的 UI 风格。
cube-ui 是滴滴团队开发的基于 Vue.js 实现的精致移动端组件库。支持按需引入和后编译,轻量灵活,拓展性强,能够方便地基于现有组件实现二次开发。
混合开发
Flutter 是谷歌的移动端 UI 框架,可在极短的时间内构建 Android 和 IOS 尚高质量的原生级应用。Flutter 可与现有代码一块儿工做,它被世界各地的开发者和组织使用。而且 Flutter 是免费和开源的。
特色:Google 出品,能够快速构建原生 APP 应用程序。作混合应用,该框架为必选框架。
Ionic 既是一个 CSS 框架,也是一个 JavaScript UI 库。Ionic 是目前最有潜力的一款 HTML5 手机应用开发框架。经过 SASS 构建应用程序。它提供了不少 UI 组件 来邦族开发者开发强大的应用。它 使用 JavaScript MVVM 框架 和 AngularJS/Vue 来加强应用。提供给数据的双向绑定,使用它称为 Web 和移动开发者的共同选择。
微信小程序
mpvue 是美团开发的一个使用 Vue.js 开发小程序的前端框架。目前支持 微信小程序、百度智能小程序、头条小程序和支付宝小程序。框架基于 Vue.js,修改了运行时框架 runtime
和代码编译器 compiler
实现。使其可运行在小程序环境中,从而为小程序开发引入 Vue.js 开发体验。
WeUI 时一套同微信原生视觉体验一致的基础样式库。由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一。包含 button、cell、dialog、toast、article、icon等各式元素。
GitHub:https://github.com/Tencent/weui
为何须要先后端分离?
为了下降开发的复杂度,之后端为出发点,!好比:Struts、SpringMVC 等框架的使用,就是后端的 MVC 时代;
下图为 MVC 模式
流程图:
咱们这里以 SpringMVC
流程图 为例:
(图引自狂神说公众号)
图为 SpringMVC 的一个较完整的流程图,实线表示 SpringMVC框架提供的技术,不须要开发者实现,虚线表示须要开发者实现。
须要分析执行流程
DispatcherServlet 表示前置控制器,是整个 SpringMVC 的控制中心。用户发出请求,DispatcherServlet 接收请求并拦截请求。
咱们假设请求的url为:http://localhost:8080/SpringMVC/hello
如上url拆分红三部分:
http://localhost:8080:服务器域名
SpringMVC: 部署在服务器上的 web 站点
hello: 表示控制器
经过分析,如上url表示为:请求位于http://localhost:8080 上的 SpringMVC 站点的 hello 控制器
HandlerMapping 为处理器映射。DispatcherServlet 调用HandelerMapping,HandlerMapping 根据请求 url 查找 Handler。
HandlerExecution表示具体的 Handler,其主要做用是根据 url 查找控制器,如上 url 被查找控制器为 :hello。
HandlerExecution 将解析后的信息传递给 DispatcherServlet,如解析控制器映射等。
HandlerAdapter 表示处理器适配器,其按照特定的规则去执行 Handler。
Handler 让具体的 Controller 执行。
Controller 将具体的执行信息返回给 HandlerAdapter ,如 ModelAndView。
HandlerAdapter 将视图逻辑名或模型传递给 DispatcherServlet。
DispatcherServlet 调用视图解析器(ViewResolver)来解析 HandlerAdapter 传递的逻辑视图名。
视图解析器将解析的逻辑视图名传给 DispatcherServlet。
视图解析器将解析的逻辑视图结果,调用具体的视图。
最终视图呈现给用户。
若是看不懂上面的图,这里还有SpringMVC流程图简化版的图:
当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,建立数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器。再将结果返回给请求者。
优势:
MVC 模式时一个很是好的协做模式,可以有效下降代码的耦合度。从架构尚可以让开发者明白代码应该写在哪里。为了让 View 更纯粹,还能够使用 Thymeleaf、Freemark 等模板引擎,使模板里没法写入 Java 代码,让先后端分工更加清晰。
缺点:
Controller
。页面路由等功能本应该是前端最关注的,但倒是由后端来实现。Controller
自己与 Model
每每也会纠缠不清,看了让人咬牙的业务代码常常会出如今 Controller
层。这些问题不能归结于程序员的素养,不然 JSP 就够了。 2005 年,AJAX(Asynchronous JavaScript And Xml,异步 JavaScript 和 XML)被正式提出,并开始使用 CDN
做为静态资源存储。因而出现了 JavaScript 王者归来(在这以前,JS 都是用来在网页上贴狗皮膏药广告的)的 SPA (Single Page Application) 单页面应用时代。
优势:
这种模式下,先后端的分工很是清晰,先后端的关键协做点是 AJAX 接口,看起来是如此美妙。但回过头来看的话,这与 JSP 时代区别不大。复杂度从服务端的 JSP 里移到了浏览器的 JavaScript。浏览器端变得很复杂。相似 SpringMVC ,这个时代开始出现浏览器端的分层架构。
缺点:
此处的 MV* 模式以下:
为了下降前端开发的复杂度,涌现了大量的前端框架,好比:AngularJS
、React
、Vue.js
、EmberJS
等,这些框架总的原则是先按类型分层,好比 Templates、Controllers、Models,而后再在层内作切分。
优势:
缺点:
前端为主的 MV* 模式解决了不少问题。但如上所述,一就存在很多不足之处。随着 NodeJS 的兴起,JavaScript 开始由能力运行在服务端。这意味着能够有一种新的研发模式:
在这种研发模式下,先后端的职责很清晰。对前端来讲,两个 UI 各司其职:
经过 Node、Web Server 层也是 JavaScript 代码,这意味着部分代码可先后复用,须要 Seo 的场景能够在服务端同步渲染,因为异步请求太多致使的性能问题也能够经过服务端来缓解。前一种模式的不足,经过这种模式几乎都能完美解决掉。
与 JSP 模式相比,全栈模式看起来是一种回归,也的确是一种向原始开发模式的回归,不过是一种螺旋上升式的回归。
基于 NodeJS 的全栈模式,依旧面临不少挑战:
综上所述,模式也好,技术也罢,没有好坏优劣之分,只有适合和不适合;先后端分离的开发思想主要是基于 SoC (关注度分离原则),上面种种模式,都是让先后端的职责更清晰,分工更何理高效。
MVVM (Model-View-ViewModel)是一种软件架构设计模式,由微软 WPF(用于替代 WinForm,之前就是用这个技术开发桌面应用程序的)和 Silverlight(相似于 JavaApplet,简单点说就是在浏览器上运行 WPF)的架构师 Ken-Cooper 和 Ted-Peters 开发,是一种简化用户界面的事件驱动编程方式。由 John-Gossman(一样也是 WPF 和 Silverlight 的架构师)于 2005 年在 它的博客上发表。
MVVM 源自于经典的 MVC(Model-View-Controller)模式。MVVM 的核心是 ViewModel 层,负责转换 Model 中的数据对象来让数据变得更容易管理和使用,其做用以下:
MVVM 已经至关成熟了,主要应用但不只仅在网络应用程序开发中。当下流行的 MVVM 框架有 Vue.js
,Angular.js
等。
MVVM 模式和 MVC 模式同样,主要目的是分离视图(View)和模型(Model)。有如下几大好处:
View 是视图层,也就是用户界面。前端主要由 HTML 和 CSS 来构建,为了更方便地展示 ViewModel
或者 Model
层的数据,已经产生了各类各样的先后端模板语言,好比 FreeMark、Thymeleaf 等等,各大 MVVM 框架 如 Vue,js,AugularJS,EJS 等也都有本身用来构建用户界面的内置模板语言。
Model 是指数据模型,泛指后端进行的各类业务逻辑处理和数据操控。主要围绕数据库系统展开。这里的难点主要在于须要和前端约定统一的接口规则
ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model 数据进行转换处理,没作二次封装。以生成符合 View 层使用于其的视图数据模型。
须要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和行为两部分。而 Model 层的数据模型是只包含状态的
视图状态和行为都封装在了 ViewModel 中。这样的封装使得 ViewModel 能够完整地去描述 View 层。因为实现了双向绑定,ViewModel 的内容会实时展示在 View 层,这是激动人心的,由于前端开发者不再必低效又麻烦地经过操纵 DOM 去更新视图了。
MVVM 框架已经把最脏最累地一块作好了,咱们开发者只须要处理和维护 ViewModel,更新数据视图就会自动获得相应更新,真正实现 事件驱动程序。
View 层展示地不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就彻底解耦了 View 层和 Model 层,这个解耦是相当重要的,它是先后端分离方案实施的重要一环。
在 MVVM 架构中,是不容许数据和视图直接通讯的,只能经过 ViewModel 来通讯,而 ViewModel 就是定义了一个 Observer 观察者。
至此,咱们就明白了,Vue.js 就是一个 MVVM 的实现者,它的核心就是实现了 DOM 监听与数据绑定
官网下载:
CDN:
开发版本:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
生产版本:
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
原生 ES Modules
<script type="module"> import Vue from 'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.esm.browser.js' </script>
注:开发版本中包含源代码,生产版本是删除注释和警告后压缩的js文件
idea 安装 Vue.js 插件
如果搜索不到显示search results are not loaded check the internet connection
解决方案:
若重启idea后仍是不能搜索到插件,则重启多几回,若还不行,则电脑关机后等待5分钟后重启电脑去安装插件。
若都未解决,网上有人说改用开手机热点来下载插件或离线安装插件,能够尝试一下。
导入vue.min.js ,并编写 demo1.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- View 层 模板 --> <div id="app"> // {{变量}},获取Vue对象的属性 {{msg}} </div> <!-- 导入vue.js --> <script src="../js/vue.min.js"></script> <script> var vm = new Vue({ el: "#app", data:{ msg:"hello,Vue!" } }); </script> </body> </html>
用浏览器打开这个 html 文件,并在控制台中测试 Vue 的双向绑定
在控制台中咱们使用 对象名.属性 = "修改后的值"
来实现对 vm 对象的修改。在这里,咱们输入 vm.msg="hello",页面显示内容及控制台以下图:
能够看出,咱们在控制台中修改 vm 对象,前端页面会发生改变。也就是说,如今能够在不刷新网页的基础上,实现改变后台数据,前端页面数据也改变,这就是双向绑定。
注意咱们再也不和 HTML 直接交互了。一个 Vue 应用会将其挂载到一个 DOM 元素上 (对于这个例子是 #app
) 而后对其进行彻底控制。那个 HTML 是咱们的入口,但其他都会发生在新建立的 Vue 实例内部。
咱们已经成功建立了第一个 Vue 应用!看起来这跟渲染一个字符串模板很是相似。可是, Vue 在背后作了大量工做。如今数据和 DOM 已经创建了关联,全部东西都是响应式的。咱们在控制台操做对象属性,界面能够实时更新!
咱们还能够使用 v-bind
来绑定元素特性!
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <span v-bind:title="msg"> 鼠标悬停几秒钟查看此处动态绑定的提示信息! </span> </div> <!-- 导入vue.js --> <script src="../js/vue.min.js"></script> <script> var vm = new Vue({ el: "#app", data:{ msg:'页面加载于' + new Date().toLocaleString() } }); </script> </body> </html>
这里咱们遇到了一点新东西。你看到的 v-bind
attribute被称为指令。指令带有前缀 v-
,以表示他们是 Vue 提供的特殊 attribute。它们会在渲染的 DOM 上应用特殊的响应式行为。在这里,该指令是将这个元素的tittle
和Vue 实例的 msg
保持一致。
若是咱们再像刚刚同样再控制台中修改 vm 对象中的 msg属性,鼠标停留在这个 span 标签的上方,内容也会相对应发生改变。
这个就很简单了,v-if
等于的值若是是true,则显示该标签,不然则不显示该标签
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <span v-if="flag"> 这是条件判断 </span> <span v-if="falseFlag"> 由于是false,因此看不到 </span> </div> <!-- 导入vue.js --> <script src="../js/vue.min.js"></script> <script> var vm = new Vue({ el: "#app", data:{ flag: true, falseFlag: false } }); </script> </body> </html>
页面显示以下:
v-if
还能够跟 v-else-if
和 v-else
搭配使用。(2.1.0新增的特性)实例代码以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <span v-if="msg === 'A'">A</span> <span v-else-if="msg === 'B'">B</span> <span v-else-if="msg === 'C'">C</span> <span v-else>D</span> </div> <!-- 导入vue.js --> <script src="../js/vue.min.js"></script> <script> var mv = new Vue({ el: "#app", data: { msg : 'B' } }); </script> </body> </html>
这里前端页面显示的结果是 B
语法 v-for="数组中遍历出来的元素名称 in 数组名称"
,而后能够使用 {{...}}
获取遍历出来的元素
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <li v-for="item in items">{{item.msg}}</li> </div> <!-- 导入vue.js --> <script src="../js/vue.min.js"></script> <script> var mv = new Vue({ el: "#app", data:{ items:[ {msg:"Java"}, {msg:"Linux"}, {msg:"Python"}, {msg:"C++"} ] } }); </script> </body> </html>
在控制台里,输入 app.items.push({msg: '新项目' })
,你会发现列表最后添加了一个新项目。
循环中能够有两个参数,第二个参数为循环时的下标。具体核心代码以下:
<div id="app"> <li v-for="(item,index) in items">{{item.msg}} --> {{index}}</li> </div>
补充: v-for 会遍历出来三个值:index,key,value ,有兴趣的话能够本身百度进行了解。这里有一篇关于 这三个值对 v-bind:key 值形成差别的实验:https://www.cnblogs.com/tim100/p/7262963.html?tdsourcetag=s_pcqq_aiomsg
你可能注意到这中事件监听的方式违背了关注点分离(separation of concern) 这个长期依赖的优良传统。但没必要担忧,由于全部的 Vue.js 使劲啊处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会致使任何维护上的困难。实际上,使用 v-on
有几个好处:
语法: v-on:事件名="方法名"
v-on
指令能够监听 DOM 事件,并在触发时运行一些 JavaScript 代码。
实例以下:
<!DOCTYPE html> <html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <button v-on:click="hello">hello</button> </div> <script src="../js/vue.min.js"></script> <script> var vm = new Vue({ el: "#app", data: { }, methods: { // 方法必须定义在 Vue 的 Methods 中 hello: function (event) { alert("hello!"); } } }); </script> </body> </html>
咱们在点击 hello
这个按钮的时候,会执行 vue 对象中 methods 属性中的 hello 方法,hello 方法是用 JavaScript 写的。也就是说,v-on
指令能够监听 DOM 事件,并在触发时运行一些 JavaScript 代码。
在事件处理程序中调用 event.preventDefault()
或 event.stopPropagation()
是很是常见的需求。尽管咱们能够在方法中轻松实现这点,但更好的方式是:方法只有存粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题, Vue.js 为 v-on
提供了事件修饰符。
.stop
.prevent
.capture
.self
.once
.passive
<!-- 阻止单击事件继续传播 --> <a v-on:click.stop="doThis"></a> <!-- 提交事件再也不重载页面 --> <form v-on:submit.prevent="onSubmit"></form> <!-- 修饰符能够串联 --> <a v-on:click.stop.prevent="doThat"></a> <!-- 只有修饰符 --> <form v-on:submit.prevent></form> <!-- 添加事件监听器时使用事件捕获模式 --> <!-- 即内部元素触发的事件先在此处理,而后才交由内部元素进行处理 --> <div v-on:click.capture="doThis">...</div> <!-- 只当在 event.target 是当前元素自身时触发处理函数 --> <!-- 即事件不是从内部元素触发的 --> <div v-on:click.self="doThat">...</div>
注:使用修饰符时,顺序很重要;响应的代码会以一样的顺序产生。所以,用 v-on:click.prevent.self
会阻止全部的点击,而 v-on:click.self.prevent 只会阻止元素自身的点击。
在监听键盘事件时,咱们常常须要检查详细的按键。 Vue 容许为 v-on
在监听键盘事件时添加按键修饰符:
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` --> <input v-on:keyup.enter="submit">
你能够直接将 KeyboardEvent.key
暴露的任意有效按键名转换为 kebab-case 来做为修饰符。
<input v-on:keyup.page-down="onPageDown">
在上述示例中,处理函数只会在 $event.key
等于 PageDown
时被调用。
补充:
Vue 经常使用的7个属性
Vue.js 是一个 MVVM 框架,即数据双向绑定。即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。
值得注意的是,咱们所说的数据双向绑定,必定是对于 UI 控件来讲的,非 UI 控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。若是咱们使用 vuex
,那么数据流也是单向的,这是就会和双向数据绑定有冲突。
在 Vue,js 中,若是使用 vuex
,实际上数据仍是单向的。之因此说是数据双向绑定,这是用的 UI 空间来讲。对于咱们处理表单, Vue.js 的双向数据绑定应用起来就特别舒服了。即二者并不互斥,在全局性数据流使用单向,方便跟踪;局部性数据使用双向,简单易操做。
你能够使用 v-model
指令在表单 <input>
、 <textarea>
、 <select>
元素上建立双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。景观有些神奇,但 v-model
本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
注: v-model 会忽略全部表单元素的 value、checked、selected 特性的初始值而老是将 Vue 实例的数据做为数据来源。应该经过 JavaScript 在组件的 data 选项中声明初始值。
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <!-- 单行文本 --> <input v-model="message" placeholder="请输入文本"/> <p>Message is: {{message}}</p> </div> <!-- 导入vue.js --> <script src="../js/vue.min.js"></script> <script> var vm = new Vue({ el: "#app", data: { mess!age: '' // 必定先在 data 中声明 v-model 中的初始化 } }); </script> </body> </html>
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <!-- 多行文本 --> <span>多行文本输入的信息:</span> <p style="white-space: pre-line;">{{ mulMessage }}</p> <br> <textarea v-model="mulMessage" placeholder="请输入多行文本"></textarea> </div> <!-- 导入vue.js --> <script src="../js/vue.min.js"></script> <script> var vm = new Vue({ el: "#app", data: { mulMessage: '' } }); </script> </body> </html>
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <!-- 复选框 --> <div> <input type="checkbox" value="张三" v-model="checkName"> <label>张三</label> <input type="checkbox" value="李四" v-model="checkName"> <label>李四</label> <input type="checkbox" value="王五" v-model="checkName"> <label>王五</label> <p>你选的是:{{checkName}}</p> </div> </div> <!-- 导入vue.js --> <script src="../js/vue.min.js"></script> <script> var vm = new Vue({ el: "#app", data: { checkName: [] } }); </script> </body> </html>
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <!-- 单选按钮 --> <div> <p>性别:</p> <input type="radio" value="男" v-model="sex"> <label>男</label> <input type="radio" value="女" v-model="sex"> <label>女</label> <p>你选择了:{{sex}}</p> </div> </div> <!-- 导入vue.js --> <script src="../js/vue.min.js"></script> <script> var vm = new Vue({ el: "#app", data: { sex: '' } }); </script> </body> </html>
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <!-- 单选框 --> <div> <select v-model="selected"> <option disabled>请选择</option> <option >A</option> <option >B</option> <option >C</option> <option >D</option> </select> <p>你选择了:{{selected}}</p> </div> </div> <!-- 导入vue.js --> <script src="../js/vue.min.js"></script> <script> var vm = new Vue({ el: "#app", data: { selected: '' } }); </script> </body> </html>
注:若是 v-model
表达式的初始值未能匹配任何选项, <select>
元素将被渲染为“未选中”状态。在 ios 中,这会使用户没法选择第一个选项。由于这样的状况下, ios 不会触发 change 事件。所以,更推荐像上面这样提供一个值为空的禁用选项。
能够使用 v-for 动态渲染(绑定到一个数组),核心代码以下:
<select v-model="selected"> <option v-for="option in options" v-bind:value="option.value"> {{ option.text }} </option> </select> <span>Selected: {{ selected }}</span> new Vue({ el: '...', data: { selected: 'A', options: [ { text: 'One', value: 'A' }, { text: 'Two', value: 'B' }, { text: 'Three', value: 'C' } ] } })
.lazy
在默认状况下, v-model
在每次 input
事件触发后将输入框的值与数据进行同步(除了8.3.1输入法组合文字时)。你能够添加上 lazy
修饰符,从而转为在 change
事件以后进行同步:
<!-- 在“change”时而非“input”时更新 --> <input v-model.lazy="msg">
.number
若是像自动将用户的输入值转为数值类型,能够给 v-model
添加 number
修饰
<input v-model.number="age" type="number">
这一般颇有用,由于即便在 type="number"
时,HTML 输入元素的值也总会发挥字符串。若是这个值没法被 parseFloat()
解析,则会返回原始的值
.trim
若是要自动过滤用户输入的首尾空白字符,能够给 v-model
添加 trim
修饰符:
组件是可复用的 Vue 实例,说白了就是一组能够重复使用的模板,跟 JSTL 的自定义标签、Thymeleaf 的 th:fragment
等框架有着殊途同归之妙。一般一个应用会以一棵嵌套的组件树的形式来组织:
例如,你可能会有页头、侧边栏、内容区等组件,每一个组件又包含了其它的像导航链接、博文之类的组件。
注:在实际开发中,咱们并不会用上面的方式开发组件,而是采用 vue-cli 建立 .vue 模板文件的方式开发,如下方法知识为了让你们理解什么是组件。
使用 Vue.component()
方法注册组件,格式以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <li-list v-for="item in items" v-bind:language="item"></li-list> </div> <!-- 引入 vue.js --> <script src="../js/vue.min.js"></script> <script> /* 使用 component() 方法注册组件 */ Vue.component('li-list',{ props: ['language'], template: "<li>{{language}}</li>" }); new Vue({ el: "#app", data:{ items: ["Java","Linux","JavaScript"] }, }); </script> </body> </html>
说明:
由于组件是可复用的 Vue 实例,因此他们与 new Vue
接收相同的选项,例如 data
、computed
、watch
、methods
以及生命周期钩子等。仅有的例外是像 el
这样根实例特有的选项。注:new Vue
必需要在所有组件注册完后再建立!不然 new Vue
后面注册的组件将不会生效。
你能够将组件进行任意次数的复用:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <click-component></click-component> <click-component></click-component> <click-component></click-component> </div> <!-- 引入 vue.js --> <script src="../js/vue.min.js"></script> <script> Vue.component('click-component',{ data: function () { return{ count: 0 } }, template: '<button v-on:click="count++">已经点击了{{ count }}次</button>' }); vm = new Vue({ el: "#app" }); </script> </body> </html>
当点击按钮时,每一个组件都会各自独立维护它的 count
。由于每用一次组件,就会又它的新实例被建立
data
组件中的 data
选项必须是一个函数,所以每一个实例能够维护一份被返回对象的独立的拷贝。若是 Vue 没有这条规则,点击一个按钮就可能会改变全部按钮中的 count
。
Axios 是一个开源的能够用在浏览器端和 NodeJS
的异步通讯框架。它的主要做用就是实现 AJAX 异步通讯,其功能特色以下:
XMLHttpRequest
GitHub:https://github.com/axios/axios
因为 Vue.js 是一个视图层框架,而且做者严格遵照 SoC(关注度分离原则),因此 Vue.js 并不包含 AJAX 的通讯功能。为了解决通讯问题,做者单独开发了一个名为 vue-resource
的插件。不过在进入 2.x 版本之后中止了对该插件的维护并推荐了 Axios
框架,少用 jQuery,由于它操纵 DOM 太频繁了!
咱们开发的接口大部分都是采用 JSON 格式,能够如今项目里模拟一段 JSON 数据,数据内容以下:建立一个名为 data.json 的文件并填入上面的内容,放在项目根目录下:
data.json
{ "name": "bilibili", "url": "www.bilibili.com", "page": 1, "isNonProfit": true, "address": { "street": "黄石路", "city": "广州市", "country": "中国" }, "links": [ { "name": "百度", "url": "www.baidu.com" }, { "name": "谷歌", "url": "www.google.com" } ] }
引入 axios
npm install --save axios vue-axios -g
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
经过 axios 获取 data.json
<!DOCTYPE html> <html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 解决闪烁问题 --> <style> [v-clack]{ display: none; } </style> </head> <body> <div id="app" v-clack> <div> {{info}} </div> <a v-bind:href="info.url">跳转</a> </div> <!-- 导入 vue.js --> <script src="../js/vue.min.js"></script> <!-- 导入 axios --> <script src="../js/axios.min.js"></script> <script> var vm = new Vue({ el: "#app", data(){ return { // 请求的返回参数格式,必须和json字符串同样 name: null, address: { country: null, city: null, street: null }, url: null } }, mounted() { axios.get("../../data.json").then(response => (this.info = response.data)) } }); </script> </body> </html>
说明:
Vue 实例有一个完整的生命周期,也就是从建立、初始化数据、编译模板、挂载 DOM、渲染 -> 更新 -> 渲染,卸载等一系列过程,咱们称这是 Vue 的生命周期。通俗地说就是 Vue 实例从建立到销毁的过程,就是生命周期。
每一个 Vue 实例在被建立时都要通过一系列的初始化过程,例如,须要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程当中也会运行一些叫作生命周期钩子的函数,这给了用户在不一样阶段添加本身的代码的机会。
好比 10.3 中就使用了钩子函数 mounted 来实现 axios 获取的数据绑定到 data() 的属性。
也有一些其它的钩子,在实例生命周期的不一样阶段被调用,如 created
、updated
、destroyed
。生命周期钩子的 this
上下文指向调用它的 Vue 实例。
注:不要再选项 property 或回调上使用箭头函数,好比 created: () => console.log(this.msg)
,或 vm.$watch('msg', newValue => this.myMethod())
。由于箭头函数并无 this
,this
会做为变量一致向上级语法做用域查找,直至找到为止,常常致使Uncaught TypeError: Cannot read property of undefined
或 Uncaught TypeError: this.myMethod is not a function
之类的错误。
生命周期图示
下图展现了实例的生命周期,随着你的不断学习和使用,它的参考价值会愈来愈高。
计算属性的重点突出在 属性
两个字上(属性是名词)。首先它是个 属性
,其次这个属性有 计算
的能力(计算式动词),这里的 计算
就是个函数:简单点说,它就是一个可以计算结果缓存起来的属性(将行为转化成静态属性),仅此而已:能够想象为缓存!
内存中运行:虚拟 DOM。计算属性式 Vue 的特点!
直接看代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <div>当前时间1:{{currentTime()}}</div> <div>当前时间2:{{currentTime1}}</div> <div>{{msg}}</div> </div> <script src="../js/vue.min.js"></script> <script> var vm = new Vue({ el: "#app", data: { msg: '修改前,计算书属性在缓存中不会改变' }, methods: { currentTime: function () { return Date.now(); } }, computed: { /* methods 中的方法名和 computed 中的方法名不能重名 重名的时候只会调用 methods 中的方法 */ currentTime1: function () { // 此处演示中,msg发生了修改 this.msg; return Date.now(); } } }); </script> </body> </html>
打开控制台测试截图以下:
注意:methods 和 computed 中的方法名不能重名
说明:
经过上图,咱们能很是清楚的看出:在调用方法时,methods 中方法的返回值一直在改变,而计算属性中的方法的返回值并无发生改变,这是由于计算属性在内存中运行,是虚拟 DOM。计算属性只有在方法中内容修改的时候,才会刷新缓存,方法的返回值才会发生改变。
结论:
调用方法时,每次都须要进行计算。既然有计算过程,则一定产生系统开销。那若是这个结果是不常常变化的呢?此时就能够考虑将这个结果缓存起来,采用计算属性能够很方便作到这一点。计算属性的主要特性就是为了将不常常变化的计算结果进行缓存,以节约咱们的系统开销!
在 Vue.js 中咱们使用 <slot>
元素做为承载分发内容的出口,翻译过来就是插槽,能够应用在组合组件的场景中。实例代码以下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- view层 --> <div id="app"> <todo > <!-- 往 slot 插槽中插入 language-title 组件 slot="language-title" : 将组件 language-title(<language-title></language-title>) 绑定 todo组件中 name="language-title" 的插槽 : 是 v-bind: 的简写,就像 $ 是 jQuery 的简写同样 :title="title" :title 是用来绑定组件language-title中的title属性 ="title" 是给组件中的title属性赋给 Vue实例中的data属性中title变量的值 --> <language-title slot="language-title" :title="title"></language-title> <!-- 往 slot 插槽中插入 language-li 组件 slot="language-li" : 将组件 language-li(<language-li></language-li>) 绑定 todo组件中 name="language-li" 的插槽 :language="language" :language 是用来绑定组件language-li中的language属性 ="language" 是给组件中的title属性赋给 v-for循环中获取的language --> <language-li slot="language-li" :language="language" v-for="language in languages"></language-li> </todo> </div> <script src="../js/vue.min.js"></script> <script> /* todo组件 */ Vue.component('todo',{ template: /* ‘\’表明换行 */ '<div>\ <slot name="language-title"></slot>\ <ul>\ <slot name="language-li"></slot>\ </ul>\ \</div>' }); /* language-title 组件 */ Vue.component('language-title',{ props: ['title'], template: '<div>{{title}}</div>' }); /* language-li 组件 */ Vue.component('language-li',{ props: ['language'], template: '<li>\ {{language}}\ \</li>' }); /* Vue 实例 */ new Vue({ el: "#app", data: { title: '编程语言', languages: ['Java','C++','JavaScript','Python'] } }); </script> </body> </html>
说明:
<slot></slot>
标签订义,上面代码中 <slot name="language-title"></slot>
和 <slot name="language-li"></slot>
就是定义插槽名字。没定义或者使用时写错插槽名字,则没法使用该插槽。:title="title"
: :title
是用来绑定组件language-title中的title属性 ="title"
是给组件中的title属性赋给 Vue实例中的data属性中title变量的值。:language="language"
: :language
是用来绑定组件language-li中的language属性 ="language"
是给组件中的title属性赋给 v-for循环中获取的language上面代码书写步骤:
el:
绑定 View 层,在 data属性中定义须要展现的数据。props
获取 View 层的变量,并在 template 中写好插槽中的模板或预留插槽。 经过上面代码能够发现,数据项在 Vue 得实例中,但删除操做要在组件中完成,那么组件如何才嗯那个删除 Vue 实例中得数据呢? 此时就涉及到参数传递与事件分发了。Vue 为咱们提供了自定义事件得功能能很好地帮助咱们解决这个问题。使用 this.$emit('自定义事件名',参数),操做具体以下:
在 Vue 实例中,增长 methods 对象并定义一个名为 removeLanguage1 的方法
new Vue({ el: "#app", data: { title: '编程语言', languages: ['Java','C++','JavaScript','Python','PHP'] }, methods: { removeLanguage1 : function (index) { this.languages.splice(index,1); } } });
在组件 language-li 增长 methods 对象,并定义一个名为 removeLanguage2 的方法
Vue.component('language-li',{ props: ['language','index','key'], // 只能绑定当前组件的方法 template: '<li>{{index}} ---> {{language}}<button @click="deleteLanguage2">删除</button></li>', methods: { deleteLanguage2: function (index) { // this.$emit : 自定义事件分发 this.$emit('remove',index) } } });
在 Vue 层定义自定义事件,并绑定 Vue 实例中的事件方法
<div id="app"> <todo> <language-title slot="language-title" :title="title"></language-title> <!-- @remove="removeLanguage1(index)" 绑定自定义事件,使得组件能够使用 Vue 实例中的方法 --> <language-li slot="language-li" v-for="(language,index) in languages" :language="language" :index="index" @remove="removeLanguage1(index)"></language-li> </todo> </div>
完整测试代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <todo> <language-title slot="language-title" :title="title"></language-title> <!-- @remove="removeLanguage1(index)" 绑定自定义事件,使得组件能够使用 Vue 实例中的方法 --> <language-li slot="language-li" v-for="(language,index) in languages" :language="language" :index="index" @remove="removeLanguage1(index)"></language-li> </todo> </div> <script src="../js/vue.min.js"></script> <script> Vue.component('todo',{ template: '<div>\ <slot name="language-title"></slot>\ <ul>\ <slot name="language-li"></slot>\ </ul>\ </div>' }); Vue.component('language-title',{ props: ['title'], template: '<div>{{title}}</div>' }); Vue.component('language-li',{ props: ['language','index','key'], // 只能绑定当前组件的方法 template: '<li>{{index}} ---> {{key}} ---> {{language}}<button @click="deleteLanguage2">删除</button></li>', methods: { deleteLanguage2: function (index) { // this.$emit : 自定义事件分发 this.$emit('remove',index) } } }); new Vue({ el: "#app", data: { title: '编程语言', languages: ['Java','C++','JavaScript','Python','PHP'] }, methods: { removeLanguage1 : function (index) { this.languages.splice(index,1); } } }); </script> </body> </html>
vue-cli 官方提供的一个脚手架,用于快速生成一个 vue 的项目模板;
预先定义好的目录结构及基础代码,就比如咋门在建立 Maven 项目时能够选择建立一个骨架项目,这个骨架项目就是脚手架,让咱们的开发更加的快速;
主要的功能:
傻瓜式安装 Node.js,除了安装路径不想安装c盘外,所有均可以点 下一步。
确认 node.js 是否安装成功:
这个 npm,就是一个软件包管理工具,就和 python 中 pip,Linux 中 apt 软件安装差很少。
Node.js 换源:使用淘宝镜像加速器 (cnpm)
换国内源,可让下载速度提高。
# -g 就是全局安装 npm install -g cnpm --registry=https://registry.npm.taobao.org # 永久更换源(使用淘宝镜像下载时能够直接使用npm而非cnpm) npm config set registry https://registry.npm.taobao.org
安装 vue-cli :
npm install vue-cli -g
dos 窗口以管理员身份运行,而后进入须要建立程序的目录,这里演示路径 D:\Code\code\h5\first-vue-cli
输入命令 vue init webpack "项目名"(这里演示项目名为 myvue)
vue init webpack myvue
进入 myvue 目录,并安装项目依赖。安装项目的依赖信息存在项目的 package.json
文件中,执行命令后,会去 package.json
文件中查找依赖安装。
# 进入myvue 目录 cd myvue # 安装依赖 npm install
启动 vue-cli 程序,并查看是否启动成功
# 启动 vue-cli 程序 npm run dev
启动程序后,根据启动的地址去访问,若出现以下页面,则表明程序建立启动成功。咱们的第一个 vue-cli 程序就建立好了!
本质上, webpack 是一个现代 JavaScript 应用的静态模块打包器(modeule bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序须要的每一个木块,而后将全部这些模块打包成一个或多个bundle。
Webpack 是当下热门的前端资源模块化管理和打包工具,它能够将许多松散耦合的木块按照依赖和规则打包称符合生产环境部署的前端资源。还能够按需加载的木块进行代码分离,等到实际须要时再异步加载。经过 loader 转换,任何形式的资源均可以看成模块。好比 ComminsJS、AMD、ES六、CSS、JSON、CoffeeScript、LESS等。
伴随着移动互联网的大潮,当今愈来愈多的网站已经从网页模式进化到了 WebApp 模式。他们运行在现代浏览器里,使用 HTML五、CSS三、ES6 等新的技术来开发丰富的功能。网页已经不只仅是完成浏览器的基本需求。WebApp 一般是一个 SPA (单页面应用),每个视图经过异步的方式加载,这致使页面初始化和使用过程当中会加载愈来愈多的 JS 代码,这给前端的开发流程和资源组织带来了巨大挑战。
前端开发和其它开发工做的主要区别:首先是前端基于多语言、多层次的编码和组织工做;其次,前端产品的交互式基于浏览器的,这些资源式经过增量加载的方式运行到浏览器端。如何在开发环境组织好这些碎片化的代码和资源,而且保证他们在浏览器端快速、优雅地加载和更新,就须要一个模块化系统,这个理想中地模块化系统式前端工程师多年来一直探索地难题。
<script src="module1.js"></script> <script src="module2.js"></script> <script src="module3.js"></script>
这是最原始的 JavaScript 文件加载的方式。若是把每个文件看做是一个模块,那么他们的接口一般是暴露在全局做用域下。也就是说定义在 window 对象中,不一样模块的调用都是一个做用域。
这种原始的加载方式暴露了一些显而易见的弊端:
<script>
的书写顺序进行加载 服务器端的 NodeJS 遵循 ConmmonsJS 规范,该规范核心思想是容许模块经过 require
方法来同步加载所需依赖的其它模块,而后经过 exports
或 module.exports
来导出须要暴露的接口。
优势:
缺点:
实现:
Asynchronous Module Definition 规范其实主要是一个主要接口 define(id?。dependencies?,factory);它要生命模块的时候指定全部的依赖 dependencies ,而且要看成形参传到 factory 中,对于模块提早执行。
define("module",["dep1","dep2]),function(d1,d2){ return someExportedBalue; }); require(["module","../file,js"]),function(module, file {});
优势:
缺点:
实现:
Commons Modules Definition 规范和 AMD 很类似,尽可能保持简单,并与 CommonsJS 和 NodeJS 和 Modules 规范保持了很大的兼容性
define(function(require,exports,module)){ var $ = require("jquery"); var Spinning = require("./spinning"); exports.doSomething = ....; }
优势:
缺点:
实现
EcmaScipt6 标准增长了 JavaScript 语言层面的模板体系定义。 ES6 模块的设计思想,是尽可能静态化,使编译时就能肯定模块的依赖关系,以及输入和输出的变量。CommonsJS 和 AMD 模块都只能在运行时肯定这些东西。
import "jquery"; exports function doStuff(){} module "locaModule" {}
优势:
缺点:
实现:
你们指望的模块系统
能够兼容多种模块风格,尽可能能够利用已有代码,不只仅是 JavaScript 模块化,还有 CSS、图片、字体等资源也须要模块化
WebPack 是一款模块加载器兼打包工具,它能把各类资源,入 JS、JSX、ES六、SASS、LESS、图片等都做为模块来处理和使用。
安装:
npm install webpack -g npm install webpack-cli -g
测试安装成功:
webpack -v webpack-cli -v
配置:
建立 webpack.config.js
配置文件
module.exports = { entry = "", output: { path: "", filename: "" }, module:{ loaders: { {test: /\.js$/, loader: ""} } }, plugins:{}, resolve:{}, watch: true }
直接运行 webpack
命令打包
建立项目(跟 vue-cli 项目差很少,先建立一个文件夹,而后用idea打开)
建立一个名为 modules 的目录,用于放置 JS 模块等静态资源
在 modules 目录下建立模块文件,如 hello.js ,用于编写 JS 模块相关的代码
// 暴露一个方法:hello exports.hello = function () { document.write("<h1>hello,webpack</h1>"); };
在 modules 目录下建立一个名为 main.js 的入口文件,用于打包时设置 entry 属性
// require 导入一个模块,就能够调用这个模块中的方法了 var hello = require("./hello"); hello.hello();
在项目根目录下建立 webpack.comnfig.js 配置文件,使用 webpack 命令打包
module.exports = { entry: './modules/main.js', output:{ filename: "./js/bundle.js" } };
注:webpack.config.js 的名字不能写错,还有 webpack.config.js 文件必须放在项目根目录下!
此时,项目会生成 dist/js 目录,并生成了 bundle.js 文件,bundle.js 文件就是打包后的 js 文件,里面的代码是用 ES5 规范书写的
在项目根目录下建立 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 能够对 webpack 项目进行热部署,即修改源代码后,会自动打包。
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:
基于第一个 vue-cli
进行测试学习,先看 node——modules 中是否存在 vue-router
vue- router 是一个插件包,因此咱们仍是须要用 npm/cnpm 来进行安装。打开命令行工具,进入你的项目目录,输入下面命令。
npm install vue-router --save-dev
若是这里 error 的话,就使用 cnpm 执行这个命令。
若是在一个模块化工程中使用它,必须 经过 Vue.use() 明确地安装路由功能:
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter);
删除没有用的东西
component 目录下存放咱们本身的组件
Content.vue
<template> <h1>123</h1> </template> <script> export default { name: "Content" } </script> <style scoped> </style>
Main.vue
<template> <h1>首页</h1> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
建立文件加 router ,并在该文件夹下建立 index.js 配置路由
index.js
import Vue from 'vue' import VueRouter from 'vue-router' // 导入组件 import Content from '../components/Content' import Main from '../components/Main' // 安装路由 Vue.use(VueRouter); // 配置导出路由 export default new VueRouter({ routes: [ // 这里是routes,不是routers,单词不要写错!不然 router-view 将不会渲染 { // 路由路径 path: '/content', // 路由名字,能够省略 name: 'content', // 路由组件 component: Content }, { path: '/main', name: 'main', component: Main } ] });
在 main.js 中配置路由
main.js
import Vue from 'vue' import App from './App' // 导入router import router from './router' Vue.config.productionTip = false; new Vue({ el: '#app', // 配置路由 router, // 这里是 router,自定义命名须要以键值对的形式在 vue 实例中声明 components: { App }, template: '<App/>' });
在 App.vue 中测试路由是否配置成功
<template> <div id="app"> <h1>hello,vue</h1> <router-link to="/main">首页</router-link> <router-link to="/content">内容页</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>
说明:
routes
而不是 routers
,注意单词拼写,不然 <router-view></router-view>
视图将不会渲染Vue | Error in render: "TypeError: Cannot read property 'matched' of undefined"
的错路由模式有两种
修改路由配置,代码以下:
export default new Router({ mode: 'history', routes: [ .... ] });
处理 404
建立一个名为 NotFound.vue 的视图组件
<template> <h1>404,你的页面走丢了!</h1> </template> <script> export default { name: "NotFound" } </script> <style scoped> </style>
在路由的中配置一个 404 的路由
import NotFound from '../components/NotFound'; { path: '*', component: NotFound }
咱们结合 ElementUI 组件库,将所须要的知识点应用到实际中,以最快的速度来掌握 Vue 的使用。
dos 窗口进入到须要建立工程的文件夹
建立工程,导入依赖
# 建立工程项目 vue init webpack 工程名 # 安装开发环境 npm install vue-router // 安装 vue-router npm i element-ui -S // 安装 element-ui cnpm install sass-loader node-sass --save-dev // 安装 SASS,建议使用 国内员安装 npm install // 安装依赖
启动项目,查看是否安装成功
npm run dev
删除多余的配置和组件,编写须要的组件
Main.vue
<template> <h1>主页</h1> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
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"); } else { this.dialogVisible = true; return false; } }); } } } </script> <style 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>
建立文件夹 router ,并配置路由 index.js
index.js
import Vue from 'vue'; import Router from 'vue-router'; import Login from '../components/Login'; import Main from '../components/Main'; Vue.use(Router); export default new Router({ routes: [ { path: '/main', name: 'main', component: Main }, { path: '/login', name: 'login', component: Login } ] });
在 main.js 中注册 Element-UI 和 路由器
import Vue from 'vue' import App from './App' // 导入element-ui import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import router from './router' Vue.use(ElementUI); Vue.config.productionTip = false; /* eslint-disable no-new */ new Vue({ el: '#app', router, components: { App }, template: '<App/>' });
验证
App.vue
<template> <div id="app"> <h1>app</h1> <router-link to="/main">主页</router-link> <router-link to="/login">登陆</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>
标签 | 解释 |
---|---|
el-col | 总体,默认占24栅格 |
el-container | 主题区域 |
el-tooltip | 提示框信息 |
el-header | 内容头部区域 |
el-aside | 左侧内容区域 |
el-main | 主要内容区域 |
el-menu | 整个导航栏 |
el-submenu | 单独一个导航栏 |
el-menu-item | 单独一个导航栏里面的单独一个栏目 |
el-menu-item-group | 一组导航栏 el-date-picker 组件事件格式化方式 |
el-dialog | 弹出对话框 |
el-table | 表格 |
el-table-column | 表格列 |
el-pagination | 新增分页 |
el-select | 选择框 |
el-button | 按钮 |
el-form | 表单提交 |
el-form-item lable = "活动区域" | 表单域 |
el-input-number : (@change = handlechange -- change 事件) | 数字输入框,能够实现加减 |
el-tab-pane | 是 el-table 的分页 |
嵌套路由又称子路由,在实际应用中,一般由多层嵌套的组件组合而成。一样的,URL 中各端动态路径也按某种结构对应嵌套的各层组件。
根据上面的路由工程项目为基础,增长嵌套路由。
增长须要使用的组件
PrivateInfo.vue
<template> <h1>信息页</h1> </template> <script> export default { name: "info" } </script> <style scoped> </style>
TeamInfo.vue
<template> <h1>团队信息</h1> </template> <script> export default { name: "Team" } </script> <style scoped> </style>
编写路由展现页面
代码是从 ElementUI 官网上拷贝后修改了一些内容,并放到 Main.vue 中
Main.vue
<template> <div class="mainDiv"> <!-- 侧边栏 --> <div > <el-col :span="4" class="navMenuDiv"> <el-menu default-active="2" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose"> <el-submenu index="1"> <template slot="title"> <i class="el-icon-location"></i> <span>信息管理</span> </template> <el-menu-item-group> <el-menu-item index="1-1" > <router-link to="/privateInfo">我的信息</router-link> </el-menu-item> <el-menu-item index="1-2"> <router-link to="/teamInfo">团队信息</router-link> </el-menu-item> <el-menu-item index="1-3"> <router-link to="/main">返回首页</router-link> </el-menu-item> </el-menu-item-group> <el-submenu index="1-4"> <template slot="title">选项4</template> <el-menu-item index="1-4-1">选项1</el-menu-item> </el-submenu> </el-submenu> <el-menu-item index="2"> <i class="el-icon-menu"></i> <span slot="title">导航二</span> </el-menu-item> <el-menu-item index="3"> <i class="el-icon-document"></i> <span slot="title">导航三</span> </el-menu-item> <el-menu-item index="4"> <i class="el-icon-setting"></i> <span slot="title">导航四</span> </el-menu-item> </el-menu> </el-col> </div> <!-- 导航栏 --> <div > <el-col :span="20"> <el-menu :default-active="activeIndex2" class="el-menu-demo" mode="horizontal" @select="handleSelect" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" > <el-menu-item index="1">处理中心</el-menu-item> <el-submenu index="2"> <template slot="title">个人工做台</template> <el-menu-item index="2-1">选项1</el-menu-item> <el-menu-item index="2-2">选项2</el-menu-item> <el-menu-item index="2-3">选项3</el-menu-item> <el-submenu index="2-4"> <template slot="title">选项4</template> <el-menu-item index="2-4-1">选项1</el-menu-item> <el-menu-item index="2-4-2">选项2</el-menu-item> <el-menu-item index="2-4-3">选项3</el-menu-item> </el-submenu> </el-submenu> <el-menu-item index="3" disabled>消息中心</el-menu-item> <el-menu-item index="4"><a href="https://www.ele.me" target="_blank">订单管理</a></el-menu-item> </el-menu> </el-col> </div> <!-- 展现信息 --> <el-main> <router-view/> </el-main> </div> </template> <script> export default { name: "Main", data() { return { activeIndex: '1', activeIndex2: '1' }; }, methods: { handleSelect(key, keyPath) { console.log(key, keyPath); }, handleOpen(key, keyPath) { console.log(key, keyPath); }, handleClose(key, keyPath) { console.log(key, keyPath); } } } </script> <style scoped> .navMenuDiv{ text-align: left; } .mainDiv { margin-top: auto; } </style>
配置嵌套路由
index.js
import Vue from 'vue'; import Router from 'vue-router'; import Login from '../components/Login'; import Main from '../components/Main'; import PrivateInfo from '../components/PrivateInfo'; import TeamInfo from '../components/TeamInfo' Vue.use(Router); export default new Router({ routes: [ { path: '/main', component: Main, children: [ { path: '/privateInfo', component: PrivateInfo }, { path: '/teamInfo', component: TeamInfo} ] }, { path: '/login', component: Login }, ] });
说明:
启动项目,测试是否跳转
npm run dev
概念
RESTful 就是一个资源定位及资源操做的风格。不是标准,也不是协议,只是一种风格。基于这个风格设计的软件能够更简洁,更由层次,更易于实现缓存机制。
功能
资源:互联网全部事物均可以被抽象为资源。
资源操做:使用 POST、DELETE、PUT、GET,使用不一样方法对资源进行操做。分别对应 添加、删除、修改、查询。
传统方式操做资源
http://localhost:8080/item/action?id=1 或 http://localhost:8080/item/action?id=1&age=18 或 http://localhost:8080/item/action
使用 RESTful 操做资源
http://loaclhos:8080/item/1 或 http://localhost:8080/item/1/18 或 http://loaclhost:8080/item/action
经过对比能够看出,RESTful 风格更加简洁,且不会把咱们的参数信息暴露给用户,更加安全。如今大部分网站都是使用 RESTful 风格。
在上面代码的基础上进行修改
在 index.js 中修改路由的 path,使用path接收参数
import Vue from 'vue'; import Router from 'vue-router'; import Login from '../components/Login'; import Main from '../components/Main'; import PrivateInfo from '../components/PrivateInfo'; import TeamInfo from '../components/TeamInfo'; import NotFound from '../components/NotFound'; Vue.use(Router); export default new Router({ mode: 'history', routes: [ { path: '/main', component: Main, children: [ // :id :接收 URL 中传来的 id 参数 , name :视图层经过name绑定路由 { path: '/privateInfo/:id', name: 'privateInfo', component: PrivateInfo }, { path: '/teamInfo', component: TeamInfo} ] }, { path: '/login', component: Login }, { path: '/goHome', redirect: 'main' }, { path: '*', component: NotFound } ] });
说明:
/privateInfo/:id
中 :id
表示接收 URL 中传来的 id 参数name
:视图层经过 name 绑定路由修改 router-link 标签内的内容,使其可以经过 URL 将参数传到路由,而且能让 vue 实例获取到参数
<el-menu-item index="1-1" > <!-- :to :让 params 中的参数绑定到 vm 中,让组件能够经过 props 获取到, 默认是不用写 name 的,但若是须要数据传输,则须要 name 绑定路由 parms: 传递参数 --> <router-link :to="{name: 'privateInfo', params:{id: 1}}">我的信息</router-link> </el-menu-item>
说明:
:to
:让 params 中的参数绑定到 vm 中,让组件能够经过 props
获取到能够使用两种方式来获取参数
经过路由得到参数 $route.params.id
<template> <div> <h1>信息页</h1> {{ $route.params.id }} </div> </template> <script> export default { name: "info", } </script> <style scoped> </style>
经过 props 得到参数
使用这种方式前,须要在路由中开启 props 传参,让其值为 true 则是开启
// props:true :开启 props 传参,只有等于 true,组件才能经过 props 接收到路由的参数 { path: '/privateInfo/:id', name: 'privateInfo', component: PrivateInfo, props: true },
修改 PrivateInfo 的内容,让组件经过 props
接收参数。而后经过 {{ id }}
获取参数
<template> <div> <h1>信息页</h1> {{ id }} </div> </template> <script> export default { name: "info", props: ['id'] } </script> <style scoped> </style>
第二种更符合咱们 java 程序员的思惟。
beforRouteEnter
:在进入路由前执行
beforRouteLeave
:在离开路由前执行
示例代码:
<script> export default { name: "info", /* * 跟 Java 的过滤器差很少 * to:去哪里 * from:从哪来 * next:跟过滤器的 chain 差很少,若是不调用next方法,则会停在这里不会继续前进 * */ beforeRouteEnter: (to,from,next)=>{ console.log('进入路由以前'); }, beforeRouteLeave: (to,from,next)=>{ console.log('离开路由以前'); next(); }, } </script>
在开发者工具的控制台中查看效果
咱们每进一次路由,就会触发路由钩子的beforRouteEnter
,跳转到其它页面时会触发路由钩子的beforRouteLeave
参数说明:
安装 Axios
npm install --save axios vue-axios
main.js 引入 Axios
// 引入 Axios import axios from 'axios'; import VueAxios from 'vue-axios';
将data.json 文件放在 static/mock 文件夹内,并在 beforRouteEnter 中进行异步加载
data.json
{ "name": "bilibili", "url": "www.bilibili.com", "page": 1, "isNonProfit": true, "address": { "street": "黄石路", "city": "广州市", "country": "中国" }, "links": [ { "name": "百度", "url": "www.baidu.com" }, { "name": "谷歌", "url": "www.google.com" } ] }
beforRouteEnter 中进行异步加载
<template> <div> <h1>信息页</h1> {{ id }} </div> </template> <script> export default { name: "info", props: ['id'], /* * 跟 Java 的过滤器差很少 * to:去哪里 * from:从哪来 * next:跟过滤器的 chain 差很少 * */ beforeRouteEnter: (to,from,next)=>{ console.log('进入路由以前'); next(vm => { vm.getData(); // 进入路由以前执行 getData }); next(); }, beforeRouteLeave: (to,from,next)=>{ console.log('离开路由以前'); next(); }, methods: { getData : function () { this.axios.get('../static/mock/data.json').then(function (response) { console.log(response.data); }); } } } </script> <style scoped> </style>
测试,并在控制台中查看输出