Vue (读音/vju/, 类似于view)是一套用于构建用户界面的渐进式框架,发布于2014年2月。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue的核心库只关注视图层,不仅易于上手,还便于与第三方库(如: vue-router: 跳转,vue-resource: 通信,vuex:管理)或既有项目整合。
想要成为真正的“互联网Java全栈工程师”还有很长的一段路要走,其中“我大前端”是绕不开的一门必修课。本阶段课程的主要目的就是带领我Java后台程序员认识前端、了解前端、掌握前端,为实现成为“互联网Java全栈工程师”再向前迈进一步。
前面有博客,略
CSS层叠样式表是一门标记语言,并不是编程语言,因此不可以自定义变量,不可以引用等,换句话说就是不具备任何语法支持,它主要缺陷如下:
这就导致了我们在工作中无端增加了许多工作量。为了解决这个问题,前端开发人员会使用一种称之为[CSS预处理器]的工具,提供CSS缺失的样式层复用机制、减少冗余代码,提高样式代码的可维护性。大大提高了前端在样式上的开发效率。(例如页面在不同的时候有不同的需求,淘宝在双11和618的样式就会不一样)
CSS预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为CSS增加了一些编程的特性,将CSS作为目标生成文件,然后开发者就只要使用这种语言进行CSS的编码工作。转化成通俗易懂的话来说就是“用一种专门的编程语言,进行Web页面样式设计,再通过编译器转化为正常的CSS文件,以供项目使用”
常用的CSS预处理器有哪些
JavaScript一门弱类型脚本语言,其源代码在发往客户端运行之前不需经过编译,而是将文本格式的字符代码发送给浏览器由浏览器解释运行。
Native原生JS开发
原生JS开发,也就是让我们按照**[ECMAScript]** 标准的开发方式,简称是ES,特点是所有浏览器都支持。截止到当前博客发布时间,ES 标准已发布如下版本:
区别就是逐步增加新特性。
TypeScript是一种由微软开发的自由和开源的编程语言。它是JavaScript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。由安德斯海尔斯伯格(C#、Delphi、TypeScript 之父; .NET 创立者)主导。
该语言的特点就是除了具备ES的特性之外还纳入了许多不在标准范围内的新特性,所以会导致很多浏览器不能直接支持TypeScript语法,需要编译后(编译成JS)才能被浏览器正确执行。
前端三大框架:Angular、React、Vue
注:以上知识点将WebApp开发所需技能全部梳理完毕
主要目的是实现一套代码三端统一(PC、Android:.apk、iOS:.ipa )并能备够调用到底层件(如:传感器、GPS、 摄像头等),打包方式主要有以下两种:
详见微信官网:这里就是介绍一个方便微信小程序UI开发的框架:WeUI
前端人员为了方便开发也需要掌握一定的后端技术, 但我们Java后台人员知道后台知识体系极其庞大复杂,所以为了方便前端人员开发后台应用,就出现了NodeJS这样的技术。
NodeJS的作者已经声称放弃NodeJS (说是架构做的不好再加上笨重的node_ modules,可能让作者不爽了吧),开始开发全新架构的Deno
既然是后台技术,那肯定也需要框架和项目管理工具,NodeJS 框架及项目管理工具如下:
iView是一个强大的基于Vue的UI库,有很多实用的基础组件比elementui的组件更丰富,主要服务于PC界面的中后台产品。使用单文件的Vue组件化开发模式 基于npm + webpack + babel 开发,支持ES2015高质量、功能丰富有好的API,自由灵活的使用空间。
备注:属于前端主流框架,选型时可考虑使用,主要特点是移动端支持较多
Element是饿了么前端开源维护的Vue UI组件库, 组件齐全, 基本涵盖后台所需的所有组件,文档讲解详细, 例子也很丰富。主要用于开发PC端的页面, 是一个质量比较高的Vue UI组件库。
备注:属于前端主流框架,选型时可考虑使用,主要特点是桌面端支持较多
飞冰是阿里巴巴团队基于React/Angular/Vue的中后台应用解决方案, 在阿里巴巴内部, 已经有270多个来自几乎所有BU的项目在使用。飞冰包含了一条从设计端到开发端的完整链路,帮助用户快速搭建属于自己的中后台应用。
官网地址:
Git hub
备注:主要组件还是以React为主, 截止2019年02月17日更新博客前对Vue的支持还不太完善,目前尚处于观望阶段
Vant UI是有赞前端团队基于有赞统一的规范实现的Vue组件库, 提供了-整套UI基础组件和业务组件。通过Vant, 可以快速搭建出风格统一的页面,提升开发效率。
at-ui是一款基于Vue 2.x的前端UI组件库, 主要用于快速开发PC网站产品。它提供了一套n pm+web pack+babel前端开发工作流程, CSS样式独立, 即使采用不同的框架实现都能保持统一的UI风格。
cube-ui是滴滴团队开发的基于Vue js实现的精致移动端组件库。支持按需引入和后编译, 轻量灵活;扩展性强,可以方便地基于现有组件实现二次开发。
Flutter是谷歌的移动端UI框架, 可在极短的时间内构建Android和iOS上高质量的原生级应用。Flutter可与现有代码一起工作, 它被世界各地的开发者和组织使用, 并且Flutter是免费和开源的。
备注:Google出品, 主要特点是快速构建原生APP应用程序, 如做混合应用该框架为必选框架
lonic既是一个CSS框架也是一个Javascript UI库, lonic是目前最有潜力的一款HTML 5手机应用开发框架。通过SASS构建应用程序, 它提供了很多UI组件来帮助开发者开发强大的应用。它使用JavaScript MV VM框架和Angular JS/Vue来增强应用。提供数据的双向绑定, 使用它成为Web和移动开发者的共同选择。
mpvue是美团开发的一个使用Vue.js
开发小程序的前端框架, 目前支持微信小程序、百度智能小程序,头条小程序和支付宝小程序。框架基于Vue.js
, 修改了的运行时框架runtime
和代码编译器compiler
实现, 使其可运行在小程序环境中, 从而为小程序开发引入了Vue.js
开发体验。
备注:完备的Vue开发体验, 井且支持多平台的小程序开发, 推荐使用
WeUI是一套同微信原生视觉体验一致的基础样式库, 由微信官方设计团队为微信内网页和微信小程序量身设计, 令用户的使用感知更加统一。包含button、cell、dialog、toast、article、icon等各式元素。
为了降低开发的复杂度, 以后端为出发点, 比如:Struts、Spring MVC等框架的使用, 就是后端的MVC时代;
以SpringMVC
流程为例:
Dispatcher Servlet
)HandlerMapping
查找Handler
,可以根据xml
配置、注解进行查找HandlerMapping
向前端控制器返回Handler
Handler
Handler
Handler
执行完成给适配器返回ModelAndView
ModelAndView
,ModelAndView
是SpringMvc
框架的一个底层对象,包括Model
和View
JSP
)View
ModelAndView
对象中)填充到request
域优点
MVC是一个非常好的协作模式, 能够有效降低代码的耦合度从架构上能够让开发者明白代码应该写在哪里。为了让View更纯粹, 还可以使用Thyme leaf、Frree marker等模板引擎, 使模板里无法写入Java代码, 让前后端分工更加清晰。
缺点
时间回到2005年A OAX(Asynchronous JavaScript And XML, 异步JavaScript和XML,老技术新用法)被正式提出并开始使用CDN作为静态资源存储, 于是出现了JavaScript王者归来(在这之前JS都是用来在网页上贴狗皮膏药广告的) 的SPA(Single Page Application) 单页面应用时代。
优点
这种模式下, **前后端的分工非常清晰, 前后端的关键协作点是AJAX接口。**看起来是如此美妙, 但回过头来看看的话, 这与JSP时代区别不大。复杂度从服务端的JSP里移到了浏览器的JavaScript,浏览器端变得很复杂。类似Spring MVC, 这个时代开始出现浏览器端的分层架构:
缺点
此处的MV*模式如下:
为了降低前端开发复杂度,涌现了大量的前端框架,比如:Angular JS
、React
、Vue.js
、Ember JS
等, 这些框架总的原则是先按类型分层, 比如Templates、Controllers、Models, 然后再在层内做切分,如下图:
优点
缺点
前端为主的MV*模式解决了很多很多问题, 但如上所述, 依旧存在不少不足之处。随着Node JS的兴起, JavaScript开始有能力运行在服务端。这意味着可以有一种新的研发模式:
在这种研发模式下,前后端的职责很清晰。对前端来说,两个UI层各司其职:
通过Node, WebServer层也是JavaScript代码, 这意味着部分代码可前后复用, 需要SEO的场景可以在服务端同步渲染,由于异步请求太多导致的性能问题也可以通过服务端来缓解。前一种模式的不足,通过这种模式几乎都能完美解决掉。
与JSP模式相比, 全栈模式看起来是一种回归, 也的确是一种向原始开发模式的回归, 不过是一种螺旋上升式的回归。
基于Node JS的全栈模式, 依旧面临很多挑战:
注:看到这里,相信很多同学就可以理解,为什么我总在课堂上说:“前端想学后台很难,而我们后端程序员学任何东西都很简单”;就是因为我们后端程序员具备相对完善的知识体系。
全栈!So Easy!
综上所述,模式也好,技术也罢,没有好坏优劣之分,只有适合不适合;前后分离的开发思想主要是基于Soc
(关注度分离原则),上面种种模式,都是让前后端的职责更清晰,分工更合理高效。
MVVM (Model-View-ViewModel) 是一种软件架构设计模式,由微软WPF (用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight (类似于Java Applet,简单点说就是在浏览器上运行的WPF)的架构师Ken Cooper和Ted Peters 开发,是一种简化用户界面的事件驱动编程方式。由John Gossman (同样也是WPF和Silverlight的架构师)于2005年在他的博客上发表。
MVVM源自于经典的MVC (ModI-View-Controller) 模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用,其作用如下:
MVVM已经相当成熟了,主要运用但不仅仅在网络应用程序开发中。当下流行的MVVM框架有Vue.js
,AngularJS
等。
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处
View是视图层,也就是用户界面。前端主要由HTML和CSS来构建,为了更方便的展现ViewModel或者Model层的数据,已经产生了各种各样的前后端模板语言,比如FreeMarker、Thymeleaf等等,各大MVVM框架如Vue.js,AngularJS,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监听与数据绑定
【说明】IDEA 可以安装 Vue 的插件!
注意:Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性。但它支持所有兼容 ECMAScript 5 的浏览器。
开发版本
CDN
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
Vue.js的核心是实现了MVVM模式,它扮演的角色就是ViewModel层,那么所谓的第一个应用程序就是展示它的数据绑定功能,操作流程如下:
1、创建一个HTML文件
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
body>
html>
2、引入Vue.js
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
3、创建一个Vue的实例
<script>
let vm = new Vue({
el:"#app",
data:{
message:"Hello Vue"
}
})
script>
说明:
el: “#app”:绑定元素的ID
data:{message:“Hello Vue”}:数据对象中有一个名为message的属性,并设置了初始值,Hello Vue
4、将数据绑定到页面元素
<div id="app">
{{message}}
div>
说明:只需要在绑定的元素中使用 双花括号 将 Vue 创建的名为 message 属性包裹起来,即可实现数据绑定功能,也就实现了 ViewModel 层所需的效果,是不是和 EL 表达式非常像?
5、完整的 HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
head>
<body>
<div id="app">
{{message}}
div>
<script>
let vm = new Vue({
el:"#app",
data:{
message:"Hello Vue"
}
})
script>
body>
html>
6、测试
为了能够更直观的体验 Vue 带来的数据绑定功能,我们需要在浏览器测试一番,操作流程如下:
1、在浏览器上运行第一个 Vue 应用程序,进入 开发者工具
2、在控制台输入 vm.message = ‘hello,vue’ ,然后 回车,你会发现浏览器中显示的内容会直接变成hello,vue
此时就可以在控制台直接输入 vm.message 来修改值,中间是可以省略 data 的,在这个操作中,我并没有主动操作 DOM,就让页面的内容发生了变化,这就是借助了 Vue 的 数据绑定 功能实现的;MVVM 模式中要求 ViewModel 层就是使用 观察者模式 来实现数据的监听与绑定,以做到数据与视图的快速响应。
我们已经成功创建了第一个Vue应用,看起来这跟渲染一个字符串模板非常类似,但是Vue在背后做了大量工作,现在数据和DOM已经被建立了关联,所有东西都是响应式的,我们在控制台操作对象属性,界面可以实时更新!
我们还可以使用v-bind来绑定元素特性
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
head>
<body>
<div id="app">
<span v-bind:title="message">欢迎学习Vuespan>
div>
<script>
let vm = new Vue({
el: "#app",
data: {
message: "Hello Vue"
}
})
script>
body>
html>
你看到的 v-bind 等被称为指令。指令带有前缀 v-,以表示它们是 Vue 提供的特殊特性。可能你已经猜到了,它们会在渲染的 DOM 上应用特殊的响应式行为。在这里,该指令的意思是:“将这个元素节点的 title 特性和 Vue 实例的 message 属性保持一致”。
如果你再次打开浏览器的 JavaScript 控制台,输入 app.message = ‘新消息’,就会再一次看到这个绑定了 title 特性的 HTML 已经进行了更新。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
head>
<body>
<div id="app">
<span v-if="score>=90">Aspan>
<span v-else-if="score>=80">Bspan>
<span v-else>Cspan>
div>
<script>
let vm = new Vue({
el: "#app",
data: {
score: 90
}
})
script>
body>
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
head>
<body>
<div id="app">
<li v-for="(item,index) in items">
{{item.name}}--{{index}}
li>
div>
<script>
let vm = new Vue({
el: "#app",
data: {
items: [
{name: "张三"},
{name: "李四"},
{name: "王五"}
]
}
})
script>
body>
html>
注:items
是数组,item
是数组元素迭代的别名。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
head>
<body>
<div id="app">
<input type="button" value="Click Me" v-on:click="sayHi">
div>
<script>
let vm = new Vue({
el:"#app",
data:{
message:"欢迎"
},
methods:{
sayHi:function () {
alert(this.message)
}
}
})
script>
body>
html>
v-on
监听事件
事件有Vue的事件、和前端页面本身的一些事件!我们这里的click
是vue的事件,可以绑定到Vue中的methods
中的方法事件!
Vue.js是一个MVVM框架, 即数据双向绑定, 即当数据发生变化的时候, 视图也就发生变化, 当视图发生变化的时候,数据也会跟着同步变化。这也算是Vue.js的精髓之处了。
值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用vue x那么数据流也是单项的,这时就会和双向数据绑定有冲突。
在Vue.js
中,如果使用vuex
, 实际上数据还是单向的, 之所以说是数据双向绑定,这是用的UI控件来说, 对于我们处理表单, Vue.js
的双向数据绑定用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪;局部性数据流使用双向,简单易操作。
你可以用v-model
指令在表单、及元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇, 但v-model
本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
注意:v-model
会忽略所有表单元素的value
、checked
、selected
特性的初始值而总是将Vue
实例的数据作为数据来源。你应该通过JavaScript
在组件的data
选项中声明初始值!
<div id="app1">
<input type="text" v-model="message1">
{{message1}}
div>
<script>
let vm1 = new Vue({
el:"#app1",
data:{
message1:""
}
})
script>
<div id="app2">
<textarea v-model="message2">textarea>
{{message2}}
div>
<script>
let vm2 = new Vue({
el:"#app2",
data:{
message2:""
}
})
script>
<div id="app3">
性别:
<input type="radio" value="男" v-model="message3">男
<input type="radio" value="女" v-model="message3">女
br>
选择了:{{message3}}
div>
<script>
let vm3 = new Vue({
el:"#app3",
data:{
message3:""
}
})
script>
<div id="app4">
爱好:
<input type="checkbox" value="健身" v-model="message4">健身
<input type="checkbox" value="学习" v-model="message4">学习
<input type="checkbox" value="敲代码" v-model="message4">敲代码
<input type="checkbox" value="听音乐" v-model="message4">听音乐
br>
选择了:{{message4}}
div>
<script>
let vm4 = new Vue({
el:"#app4",
data:{
message4:[]
}
})
script>
<div id="app5">
<select v-model="message5">
<option disabled value="">请选择option>
<option>Aoption>
<option>Boption>
<option>Coption>
select>
选择了:{{message5}}
div>
<script>
let vm5 = new Vue({
el:"#app5",
data:{
message5:""
}
})
script>
注意:v-model
表达式的初始值未能匹配任何选项,元系将被渲染为“未选中”状态。 在iOS中, 这会使用户无法选择第一个选项,因为这样的情况下,iOS不会触发change
事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
组件是可复用的Vue
实例, 说白了就是一组可以重复使用的模板, 跟JSTL
的自定义标签、Thymeleal
的th:fragment
等框架有着异曲同工之妙,通常一个应用会以一棵嵌套的组件树的形式来组织:
例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
注意:在实际开发中,我们并不会用以下方式开发组件,而是采用vue-cli
创建,vue
模板文件的方式开发,以下方法只是为了让大家理解什么是组件。
使用Vue.component()
方法注册组件,格式如下:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
head>
<body>
<div id="app">
<hello>hello>
div>
<script>
Vue.component("hello",{
template:'hello '
})
let vm = new Vue({
el:"#app",
})
script>
body>
html>
说明:
Vue.component()
:注册组件pan
:自定义组件的名字template
:组件的模板像上面那样用组件没有任何意义,所以我们是需要传递参数到组件的,此时就需要使用props
属性了!
注意:默认规则下props属性里的值不能为大写;
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
head>
<body>
<div id="app">
<names v-for="item in items" v-bind:name="item">names>
div>
<script>
Vue.component("names",{
props: ["name"],
template:'{{name}} '
})
let vm = new Vue({
el:"#app",
data:{
items:["张三","李四","王五"]
}
})
script>
body>
html>
说明:
v-for="item in items"
:遍历Vue
实例中定义的名为items
的数组,并创建同等数量的组件v-bind:panh="item"
:将遍历的item
项绑定到组件中props
定义名为item
属性上;= 号左边的panh
为props
定义的属性名,右边的为item in items
中遍历的item项的值Axios 是一个开源的可以用在浏览器端和 NodeJS 的异步通信框架,她的主要作用就是实现 AJAX 异步通信,其功能特点如下:
GitHub:https://github.com/axios/axios
中文文档:http://www.axios-js.com/
cdn:
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
由于 Vue.js 是一个 视图层框架 并且作者(尤雨溪)严格准守 SoC (关注度分离原则),所以 Vue.js 并不包含 AJAX 的通信功能,为了解决通信问题,作者单独开发了一个名为 vue-resource的插件,不过在进入 2.0 版本以后停止了对该插件的维护并推荐了 Axios 框架。少用jQuery,因为它操作Dom太频繁!
咱们开发的接口大部分都是采用 JSON 格式,可以先在项目里模拟一段 JSON 数据,数据内容如下:创建一个名为 data.json 的文件并填入上面的内容,放在项目的根目录下
{
"name":"小龙",
"url": "http://baidu.com",
"page": "1",
"isNonProfit":"true",
"address": {
"street": "东直门",
"city":"北京",
"country": "中国"
},
"links": [
{
"name": "B站",
"url": "https://www.bilibili.com/"
},
{
"name": "4399",
"url": "https://www.4399.com/"
},
{
"name": "百度",
"url": "https://www.baidu.com/"
}
]
}
测试代码
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
<style>
[v-clock]{
display: none;
}
style>
head>
<body>
<div id="app" v-cloak>
<p>姓名:{{info.name}}p>
<p>国籍:{{info.address.country}}p>
<a v-bind:href="info.links[0].url">链接a>
div>
<script>
let vm = new Vue({
el:"#app",
data(){
return{
info:{
name: null,
address:{
country: null
},
links: [{
url: null
}]
}
}
},
//钩子函数
mounted(){
axios.get("data.json").then(Response=>this.info=Response.data)
}
})
script>
body>
html>
说明:
Ajax
响应回来的数据格式匹配!官方文档:https://cn.vuejs.org/v2/guide/instance.html#生命周期图示
Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载 DOM、渲染→更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。通俗说就是 Vue 实例从创建到销毁的过程,就是生命周期。
在 Vue 的整个生命周期中,它提供了一系列的事件,可以让我们在事件触发时注册 JS 方法,可以让我们用自己注册的 JS 方法控制整个大局,在这些事件响应方法中的 this 直接指向的是 Vue 的实例。
计算属性的重点突出在 属性
两个字上(属性是名词),首先它是个 属性
其次这个属性有 计算
的能力(计算是动词),这里的 计算
就是个函数;简单点说,它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;可以想象为缓存!
上代码:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
head>
<body>
<div id="app">
<p>方法时间:{{nowTime()}}p>
<p>属性时间:{{newTime}}p>
div>
<script>
let vm = new Vue({
el:"#app",
data: {
message: 'Hello Vue'
},
methods: {
nowTime: function () {
return Date.now();
}
},
computed: {
newTime: function () {
return Date.now();
}
}
})
script>
body>
html>
说明:
结论:
调用方法时,每次都需要进行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销;
在 Vue.js
中我们使用
元素作为承载分发内容的出口,作者称其为 插槽,可以应用在组合组件的场景中;
测试
比如准备制作一个待办事项组件(books),该组件由待办标题(book-title)和待办内容(book-body)组成,但这三个组件又是相互独立的,该如何操作呢?
第一步: 定义一个待办事项的组件
<div id="app">
<books>
books>
div>
<script>
Vue.component("books",{
template: '\
待办事项
\
\
- 展示书籍
\
\
'
});
script>
第二步: 我们需要让,待办事项的标题和值实现动态绑定,怎么做呢? 我们可以留出一个插槽!
1、将上面的代码留出一个插槽,即 slot
Vue.component("books",{
template: '\
\
\
\
\
'
});
2、定义一个名为 book-title 的待办标题组件 和 book-body 的待办内容组件
Vue.component("book-title",{
props: ['title'],
template: '{{title}}
'
});
Vue.component("book-body",{
props: ['book'],
template: '{{book}} '
});
3、实例化 Vue 并初始化数据
let vm = new Vue({
el: "#app",
data: {
bookTitle: "书籍列表",
books:["java","python","linux"]
},
});
4、将这些值,通过插槽插入
<div id="app">
<books>
<book-title slot="book-title" v-bind:title="bookTitle">book-title>
<book-body slot="book-body" v-for="book in books" v-bind:book="book">book-body>
books>
div>
说明:我们的 book-title 和 book-body 组件分别被分发到了 books 组件的 book-title 和 book-body 插槽中
通过以上代码不难发现,数据项在 Vue 的实例中,但删除操作要在组件中完成,那么组件如何才能删除 Vue 实例中的数据呢?此时就涉及到参数传递与事件分发了,Vue 为我们提供了自定义事件的功能很好的帮助我们解决了这个问题;使用 this.$emit(‘自定义事件名’, 参数),操作过程如下:
1、在vue的实例中,增加了 methods 对象并定义了一个名为 removeBook 的方法
let vm = new Vue({
el: "#app",
data: {
bookTitle: "书籍列表",
books:["java","python","linux"]
},
// 该方法可以被模板中自定义事件触发
methods: {
removeBook: function (index) {
// splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目,其中 index 为添加/删除项目的位置,1 表示删除的数量
this.books.splice(index,1)
}
}
});
2、修改 book-body 待办内容组件的代码,增加一个删除按钮,并且绑定事件!
Vue.component("book-body",{
props: ['book','index'],
template: '{{book}} ',
methods: {
// 这里的 remove 是自定义事件的名称,需要在 HTML 中使用 v-on:remove 的方式指派
remove: function (index) {
this.$emit("remove",index)
}
}
});
3、修改 book-body 待办内容组件的 HTML 代码,增加一个自定义事件,比如叫 remove,可以和组件的方法绑定,然后绑定到vue的方法中!
<book-body slot="book-body" v-for="(book,index) in books" v-bind:book="book"
v-bind:index="index" v-on:remove="removeBook(index)">book-body>
逻辑理解
Vue 入门小结
核心 : 数据驱动 , 组件化
优点 : 借鉴了 AngulaJS 的模块化开发 和 React 的虚拟Dom , 虚拟Dom就是把Dom操作放到内存中执行;
常用的属性:
组件化:
组合组件 slot 插槽
组件内部绑定事件需要使用到 this.$emit(“事件名”,参数);
计算属性的特色,缓存计算数据
遵循SoC 关注度分离原则,Vue是纯粹的视图框架,并不包含,比如Ajax之类的通信功能,为了解决通信问题,我们需要使用Axios 框架做异步通信;
说明
Vue的开发都是要基于NodeJS, 实际开发采用 vue-cli脚手架开发,vue-router 路由,vuex做状态管理; Vue UI,界面我们一般使用 ElementUI(饿了么出品),或者ICE(阿里巴巴出品!)来快速搭建前端项目~
vue-cli 官方提供的一个脚手架,用于快速生成一个 vue 的项目模板;
预先定义好的目录结构及基础代码,就好比咱们在创建 Maven 项目时可以选择创建一个骨架项目,这个骨架项目就是脚手架,我们的开发更加的快速;
主要的功能:
需要的环境
确认nodejs安装成功:
node -v
,查看是否能够正确打印出版本号即可!npm-v
,查看是否能够正确打印出版本号即可!这个npm,就是一个软件包管理工具,就和linux下的apt软件安装差不多!
安装 Node.js 淘宝镜像加速器(cnpm)
这样子的话,下载会快很多~
# -g 就是全局安装
npm install cnpm -g //(推荐使用这个)
# 或使用如下语句解决 npm 速度慢的问题
npm install --registry=https://registry.npm.taobao.org
安装过程可能有点慢~,耐心等待!虽然安装了cnpm,但是尽量少用!
安装 vue-cli
cnpm install vue-cli -g
# 测试是否安装成功
# 查看可以基于哪些模板创建 vue 应用程序,通常我们选择webpack
vue list
第一个 vue-cli 应用程序
1、创建一个Vue项目,我们随便建立一个空的文件夹在电脑上
2、创建一个基于 webpack 模板的 vue 应用程序
# 这里的 myvue 是项目名称,可以根据自己的需求起名
vue init webpack myvue
一路都选择no即可;
说明:
初始化并运行
cd myvue
npm install
npm run dev
执行完成后,目录多了很多依赖
安装并运行成功后在浏览器输入:http://localhost:8080
Vue-cli目录结构
我们用IDEA,open刚才的项目!
src 目录
src
目录是项目的源码目录,所有代码都会写在这里
main.js
项目的入口文件,我们知道所有的程序都会有一个入口
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: ' '
})
import Vue from 'vue'
:ES6 写法,会被转换成 require(“vue”); (require 是 NodeJS 提供的模块加载器)import App from './App'
:意思同上,但是指定了查找路径,./ 为当前目录Vue.config.productionTip = false
:关闭浏览器控制台关于环境的相关提示new Vue({...})
:实例化 Vue
el: '#app'
:查找 index.html 中 id 为 app 的元素template: ' '
:模板,会将 index.html 中components: { App }
:引入组件,使用的是 import App from ‘./App’ 定义的 App 组件;App.vue
本质上, webpack是一个现代JavaScript应用程序的静态模块打包器(module bundler) 。当webpack处理应用程序时, 它会递归地构建一个依赖关系图(dependency graph) , 其中包含应用程序需要的每个模块, 然后将所有这些模块打包成一个或多个bundle.
Webpack是当下最热门的前端资源模块化管理和打包工具, 它可以将许多松散耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分离,等到实际需要时再异步加载。通过loader转换, 任何形式的资源都可以当做模块, 比如Commons JS、AMD、ES 6、CSS、JSON、Coffee Script、LESS等;
伴随着移动互联网的大潮, 当今越来越多的网站已经从网页模式进化到了WebApp模式。它们运行在现代浏览器里, 使用HTML 5、CSS 3、ES 6等新的技术来开发丰富的功能, 网页已经不仅仅是完成浏览器的基本需求; WebApp通常是一个SPA(单页面应用) , 每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载越来越多的JS代码,这给前端的开发流程和资源组织带来了巨大挑战。
前端开发和其他开发工作的主要区别,首先是前端基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器的,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。
Script标签
4、 安装路由,在src目录下,新建一个文件夹 : router,专门存放路由
import Vue from "vue";
// 导入路由插件
import VueRouter from "vue-router";
// 导入上面定义的组件
import Content from "../components/Content";
import Home from "../components/Home";
import My from "../components/My";
//安装路由
Vue.use(VueRouter)
//配置导出路由
export default new VueRouter({
routes: [
{
//路由路径
path: "/content",
// 路由名称
name: Content,
//跳转到哪个组件
component: Content
}
]
})
5、在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: ' '
})
6、在App.vue
中使用路由
学习Vue-Router
内容页
启动测试一下 : npm run dev
我们采用实战教学模式并结合 ElementUI
组件库,将所需知识点应用到实际中,以最快速度带领大家掌握 Vue 的使用;
创建工程
注意: 命令行都要使用管理员模式运行
1、创建一个名为 hello-vue 的工程 vue init webpack hello-vue
2、安装依赖,我们需要安装 vue-router、element-ui、sass-loader 和 node-sass 四个插件
# 进入工程目录
cd hello-vue
# 安装 vue-router
npm install vue-router --save-dev
# 安装 element-ui
npm i element-ui -S
# 安装依赖
npm install
# 安装 SASS 加载器
cnpm install sass-loader node-sass --save-dev
# 启动测试
npm run dev
3、npm命令解释:
npm install moduleName
:安装模块到项目目录下npm install -g moduleName
:-g 的意思是将模块安装到全局,具体安装到磁盘哪个位置,要看 npm config prefix 的位置npm install -save moduleName
:–save 的意思是将模块安装到项目目录下,并在 package 文件的 dependencies 节点写入依赖,-S 为该命令的缩写npm install -save-dev moduleNam
e:–save-dev 的意思是将模块安装到项目目录下,并在 package 文件的 devDependencies 节点写入依赖,-D 为该命令的缩写创建登录页面
把没有用的初始化东西删掉!
在源码目录中创建如下结构:
创建首页视图,在 views 目录下创建一个名为 Main.vue 的视图组件;
首页
创建登录页视图在 views 目录下创建一个名为 Login.vue 的视图组件,其中 el-* 的元素为 ElementUI 组件;
欢迎登录
登录
请输入账号和密码
创建路由,在 router 目录下创建一个名为 index.js 的 vue-router 路由配置文件
import Vue from 'vue'
import VueRouter from "vue-router";
import Main from "../views/Main";
import Login from "../views/Login";
Vue.use(VueRouter)
export default new VueRouter({
routes: [
{
path: "/login",
component: Login
},
{
path: "/main",
component: Main
}
]
})
配置路由,修改入口代码,修改 main.js 入口代码
import Vue from 'vue'
import App from './App'
import router from "./router"
// 导入 ElementUI
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 安装 ElementUI
Vue.use(ElementUI)
new Vue({
el: '#app',
router,
// 启用 ElementUI
render: h => h(App),
})
修改 App.vue 组件代码
首页
登录
测试 : 在浏览器打开 http://localhost:8080
如果出现错误: 可能是因为sass-loader的版本过高导致的编译错误,当前最高版本是8.x,需要退回到7.3.1 ;
去package.json文件里面的 "sass-loader"的版本更换成7.3.1,然后重新cnpm install
就可以了;
嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件,例如:
/user/foo/profile /user/foo/posts
+------------------+ +-----------------+
| User | | User |
| +--------------+ | | +-------------+ |
| | Profile | | +------------> | | Posts | |
| | | | | | | |
| +--------------+ | | +-------------+ |
+------------------+ +-----------------+
12345678
1、用户信息组件,在 views/user 目录下创建一个名为 Profile.vue 的视图组件;
个人信息
2、用户列表组件在 views/user 目录下创建一个名为 List.vue 的视图组件;
用户列表
3、配置嵌套路由修改 router 目录下的 index.js 路由配置文件,代码如下
import Vue from 'vue'
import Router from 'vue-router'
import Login from "../views/Login"
import Main from '../views/Main'
// 用于嵌套的路由组件
import UserProfile from '../views/user/Profile'
import UserList from '../views/user/List'
Vue.use(Router);
export default new Router({
routes: [
{
// 登录页
path: '/login',
name: 'Login',
component: Login
},
{
// 首页
path: '/main',
name: 'Main',
component: Main,
// 配置嵌套路由
children: [
{path: '/user/profile', component: UserProfile},
{path: '/user/list', component: UserList},
]
}
]
});
说明:主要在路由配置中增加了 children 数组配置,用于在该组件下设置嵌套路由
4、修改首页视图,我们修改 Main.vue 视图组件,此处使用了 ElementUI 布局容器组件,代码如下:
用户管理
个人信息
用户列表
内容管理
分类管理
内容列表
个人信息
退出登录
说明:
在 元素中配置了 用于展示嵌套路由,主要使用 个人信息 展示嵌套路由内容
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。此时我们就需要传递参数了;
1、修改路由配置, 主要是在 path 属性中增加了 name 这样的占位符
{
path: "/user/profile/:username",
component: UserProfile,
name: 'UserProfile'
},
2、传递参数
此时我们将 to 改为了 :to,是为了将这一属性当成对象使用,注意 router-link 中的 name 属性名称 一定要和 路由中的 name 属性名称 匹配,因为这样 Vue 才能找到对应的路由路径;
个人信息
3、接收参数, 在目标组件中
个人信息
用户名:{{$route.params.username}}
1、修改路由配置 , 主要增加了 props: true 属性
{
path: "/user/list/:userList",
component: UserList,
name: 'UserList',
props: true
},
2、传递参数和之前一样
3、接收参数为目标组件增加 props 属性
用户列表
列表:{{userList}}
重定向的意思大家都明白,但 Vue 中的重定向是作用在路径不同但组件相同的情况下,比如:
{
path: "/login",
component: Login
},
{
path: "/goLogin",
redirect: "/login"
}
说明:这里定义了两个路径,一个是 /login ,一个是 /goLogin,其中 /goLogin 重定向到了 /login 路径,由此可以看出重定向不需要定义组件;
使用的话,只需要设置对应路径即可;
重新登录
路由模式有两种
修改路由配置,代码如下:
export default new Router({
mode: 'history',
routes: [
]
});
12345
处理 404 创建一个名为 NotFound.vue
的视图组件,代码如下:
404 你要找的页面走丢了
修改路由配置,代码如下:
import NotFound from "../views/NotFound";
{
path: "/*",
component: NotFound
}
beforeRouteEnter
:在进入路由前执行
beforeRouteLeave
:在离开路由前执行
分类管理
参数说明:
在钩子函数中使用异步请求
1、安装 Axios cnpm install --save vue-axios
2、main.js
引用 Axios
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
3、准备数据 : 只有我们的 static 目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下。
// 静态数据存放的位置
static/mock/data.json
4、在 beforeRouteEnter 中进行异步请求
分类管理