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 中的数据对象来让数据变得更容易管理和使用,其作用如下:
MMVM已经相当成熟了,主要运用但不仅仅在网络应用程序开发中。当下流行的MVVM框架有Vue.js
,Angular JS
等
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处
View是视图层,也就是用户界面。前端主要由HTML
和CSS
来构建,为了更方便的展现ViewModel
或者Model
层的数据,已经产生了各种各样的前后端模板语言,比如 FreeMarker、Thymeleaf等等,各大MVVM框架和Vue.js,AugularJS,EJS等也都由自己来构建用户界面的内置模板语言。
Model是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,主要围绕数据库系统展开。这里的难点主要在于需要和前端约定统一的接口规则
ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。
需要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和行为两部分,而 Model 层的数据模型是只包含状态的
视图状态和行为都封装在了 ViewModel 里。这样的封装使得 ViewModel 可以完整地去描述View 层,由于实现了双向绑定,ViewModel 的内容会实时展现在 View 层,这是激动人心的,因为前端开发声也下必低效女麻烟地通问候纵 DOM 去更断视图。
MVVM 框架已经把最脏最累的一块做好了,我们开发者只需要外理和维护 ViewModel,更新数据视图就会自动得到相应更新,真正实现 事件驱动编程
。
View 层展现的不是 Mde
l 层的数据,而是 ViewModel
的数据,由:ViewModel 负责与 Model
层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环。
Vue (读音 /vju/,类似于 view) 是一套用于构建用户界面的渐进式框架,发布于 2014 年 2 月。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库(如:vue-router,vue-resource,vuex)或既有项目整合。
Model:模型层,在这里表示 JavaScript 对象
View:视图层,在这里表示 DOM (HTML 操作的元素)
ViewModel:连接视图和数据的中间件,Vue.js 就是 MVVM 中的 ViewModel 层的实现者
在 MVVM 架构中,是不允许 数据 和 视图 直接通信的,只能通过 ViewModel 来通信,而
ViewModel 就是定义了一个 Observer 观察者
ViewModel 能够观察到数据的变化,并对视图对应的内容进行更新
ViewModel能够监听到视图的变化,并能够通知数据发生改变
至此,我们就明白了,Vue.js 就是一个 MVVM 的实现者,他的核心就是实现了 DOM 监听 与 数
据绑定
轻量级,体积小是一个重要指标。Vue.js 压缩后有只有 20多kb (Angular 压缩后 56kb+,React 压缩后44kb+)
移动优先。更话合移动端,比如移动端的 Touch 事件
易上手,学习曲线平稳,文档齐全
吸收了Augular(模块化)和React(虚拟DOM)的长处,并拥有自己独特的g功能,如:计算属性
开源,社区活跃度高
…
【说明】IDEA 可以安装 Vue 的插件!
注意:Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性。但它支持所有兼容 ECMAScript 5 的浏览器。
开发版本
CDN
Vue.js的核心是实现MVVM模式,它扮演的角色是ViewModel层,所以所谓的第一个应用程序就是战士它的数据绑定功能
创建一个HTML文件
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
body>
html>
引入Vue.js
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
创建一个Vue的实例
<script>
var vm = new Vue({
el: "#app",
//Model:数据
data: {
message: "hello,vue!"
}
});
script>
说明:
el: "#vue"
:绑定元素的IDdata: {message: "Hello Vue!"}
:数据对象有一个名为message的属性,并设置了初始值Hello Vue!将数据绑定到页面元素
<div id="app">
{
{message}}
div>
说明:只需要在绑定的元素中使用双花括号将Vue创建的名为message属性包裹起来,即可实现数据绑定功能,也就实现了ViewModel层所需的效果,和EL表达式非常相似!
完整的HTML
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div id="app">
{
{message}}
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js">script>
<script>
var vm = new Vue({
//ViewModel
el: "#app",
//Model:数据
data: {
message: "hello,vue!"
}
});
script>
body>
html>
运行
测试
为了能够更直观的体验 Vue 带来的数据绑定功能,我们需要在浏览器测试一番,操作流程如下:
1、在浏览器上运行第一个 Vue 应用程序,进入 开发者工具
2、在控制台输入 vm.message =‘Hello World’,然后 回车,你会发现浏览器中显示的内容会直接变成 Hello World
此时就可以在控制台直接输入 vm.message 来修改值,中间是可以省略 data 的,在这个操作中,我并没有主动操作 DOM,就让页面的内容发生了变化,这就是借助了 Vue 的 数据绑定 功能实现的:MVVM 模式中要求ViewModel 层就是使用 观察者模式 来实现数据的监听与绑定,以做到数据与视图的快速响应。
我们已经成功创建了第一个Vue应用!看起来这跟渲染一个字符串模板非常相似,但是Vue在背后做了大量工作。现在数据和DOM已经被建立了关系,所有东西都是响应式的。我们在控制台操作对象属性,界面可以实时更新!
我们还可以使用v-bind
来绑定数据特性!
代码:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>zxltitle>
head>
<body>
<div id="app">
<span v-bind:title="message">
鼠标悬停几秒钟查看此动态绑定的提示信息!
span>
div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
message: '页面加载于' + new Date().toLocaleString()
}
})
script>
body>
html>
你看到的 v-bind 等被称为指令。指令带有前缀 v-,以表示它们是 Vue 提供的特殊特性。可能你 已经猜到了,它们会在渲染的 DOM 上应用特殊的响应式行为。在这里,该指令的意思是:“将这个元素节点的 title 特性和 Vue 实例的 message 属性保持一致”。
如果你再次打开浏览器的JavaScript 控制台,输入 app.messaqe =‘新消息’,就会再一次看到
这个绑定了 title 特性的 HTML 已经进行了更新。
v-if
v-else
v-else-if
代码:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>zxltitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<div id="app">
<h1 v-if="ok">YESh1>
<h1 v-else>NOh1>
<h2 v-if="type==='A'">Ah2>
<h2 v-else-if="type==='B'">Bh2>
<h2 v-else="type==='C'">Ch2>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
ok: true,
type: 'A'
}
})
script>
body>
html>
测试:
app.ok=false
,然后回车,浏览器内容变NOapp.type='B','C'
,观察浏览器内容的变化注:
使用v-*
属性绑定数据是不需要双花括号包括的
===
三个等号在JS中表示绝对等于(就是数据和类型都相等)
代码:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>zxltitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<div id="app">
<li v-for="(item, index) in items",key="index">
{
{item.message}}
li>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
items: [
{
message: '123456'},
{
message: 'zxlzxl'}
]
}
});
script>
body>
html>
注:items
是数组,item
是数组元素迭代的别名
测试:在控制台输入app.items.push({message: '987654321'})
,尝试追加数据,会发现浏览器中显示的内容增加了一条
v-on
监听事件
事件有Vue的事件、和前端页面本身的一些事件!这里click
是vue的事件,可以绑定到Vue的methods
中的方法事件!
代码:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>zxltitle>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
head>
<body>
<div id="app">
<button v-on:click="sayHi">click mebutton>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
message: "123456"
},
methods: {
//方法必须定义在Vue的Methods对象中
sayHi: function (){
alert(this.message);
}
}
});
script>
body>
html>
Vue.js 是一个 MVVM 框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是 Vue.js 的精髓之处了。
值得注意的是,我们所说的数据双向绑定,一定是对于 Ul 控件来说的,非 Ul 控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提。如果我们使用vuex
,那么数据流也是单项的,这时就会和双向数据绑定有冲突。
为什么要实现数据的双向绑定
在Vue.js
中,如果使用 vuex
,实际上数据还是单向的,之所以说是数据双向绑定,这是用的Ul 控件来说,对于我们处理表单,Vue.js 的双向数据绑定用起来就特别舒服了。即两者并不互斥,在全局性数据流使用单项,方便跟踪;局部性数据流使用双向,简单易操作。
你可以用v-model
指令在表单、
及
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
注意:v-model 会忽略所有表单元素的 value、checked、selected 特性的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值!
代码:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>zxltitle>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">script>
head>
<body>
<div id="app">
输入的文本:<input type="text" v-model="message">{
{message}}
性别:
<input type="radio" name="sex" value="男" v-model="zxl"> 男
<input type="radio" name="sex" value="女" v-model="zxl"> 女
<p>选中了谁:{
{zxl}}p>
下拉框:
<select v-model="selected">
<option value="" disabled>--请选择--option>
<option>Aoption>
<option>Boption>
<option>Coption>
select>
<p>选中了谁:{
{selected}}p>
div>
<script type="text/javascript">
var app = new Vue({
el: "#app",
data: {
zxl: "",
selected: "",
message: "123",
checked: false
}
});
script>
body>
html>
注:如果v-model
表达式的初始值未能匹配任何选项,元素将被渲染为“未选中”状态。在ios中,这会使用户无法选择第一个选项。因为这样的情况下,ios不会触发change事件。因此,更推荐像上面这样提供一个值未空的禁用选项。
组件是可服用的Vue
实例,说白了就是一组可以重复使用的模板,跟JSTL的自定义标签、Thymeleaf的th:fragment
等框架有着异曲同工之妙。通常一个应用会以一颗嵌套的组件树的形式来组织
注意:在实际开发中,我们并不会用以下方式开发组件,而是采用vue-cli创建.vue模板文件的开发方式,以下方法只是为了理解什么是组件。
例如:你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其他的像导航链接、博文之类的组件。
使用Vue.component()方法注册组件,格式如下:
<script type="text/javascript">
// 先注册组件
Vue.component("my-component-li",{
template: 'Hello li '
});
// 再实例化Vue
var vm = new Vue({
el: "#vue"
});
script>
<div id="vue">
<ul>
<my-component-li>my-component-li>
ul>
div>
说明
props
属性传递参数像上面那样用组件没有任何意义,所以我们是需要传递参数到组件的,此时就需要使用props
属性了!
注意:默认规则下props属性里面的值不能为大写
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>zxltitle>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js">script>
head>
<body>
<div id="vue">
<my-component-li v-for="zxl in items" v-bind:zhu="zxl">my-component-li>
div>
<script type="text/javascript">
//定义一个Vue组件component
Vue.component("my-component-li",{
props: ['zhu'],
template: '{
{zhu}} '
});
var app = new Vue({
el: "#vue",
data: {
items: ["Java","Linux","前端"]
}
});
script>
body>
html>
说明:
v-for="zxl in items"
:便利Vue
实例中定义的名为items
的数组,并创建同等级量的组件v-bind:zhu="zxl"
:将便利的zxl
项绑定到组件中props
定义的名为zhu
属性上;=号左边的zhu为props定义的属性名,右边的为zxl in items
中遍历的zxl项的值