01-MVVM框架概述与Vue模版语法
主要内容
- Vue介绍
- MVVM设计模式
- Vue的安装
- 数据绑定技术
- 模板语法
- v-bind绑定class
- v-bind绑定style
- 事件处理
Vue介绍
Vue是一套基于MVVM设计模式用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。
Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
MVVM设计模式
在学习认识MVVM设计模式之前,我们先来了解下MVVM的发展历史:
1995年,JavaScript在浏览器上首次设计实现。之后,浏览器就可以通过JavaScript,对页面进行一些修改。如操作HTML的DOM结构和修改CSS来实现一些动画效果。自此JavaScript经历了若干发展阶段:
- 阶段一:直接用JavaScript操作DOM节点,使用浏览器提供的原生API
- 阶段二:为了便捷开发并考虑浏览器兼容问题,jQuery以“write Less,Do More”宗旨迅速占领市场:
- 阶段三:配合服务器端实现MVC设计模式
- 现在:随着前端页面越来越复杂,用户对于交互性要求也越来越高,散乱的代码将使项目变得难以维护,仅仅用jQuery是远远不够的。MVVM模型应运而生。
MVVM本质上就是MVC 的改进版最早由微软提出,它立足于原有MVC架并且把WPF的新特性糅合进去,以应对客户日益复杂的需求变化。在前端页面中,把Model用纯JavaScript对象表示,View负责显示,两者做到了最大限度的分离。
Vue的安装
- 方法一: 在html 文件中引入vue.js
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
- 方法二: 通过npm下载vue模块
npm install -s vue
- 方法三: 通过Vue 官方脚手架 vue-cli 搭建vue组件化项目
#全局安装 vue-cli 环境变量中
npm install -g @vue/cli
# 使用 vue-cli指令搭建单页面应用项目
vue create hello-world
起步实例化一个Vue对象
介绍: Vue会为开发者提供一个名叫Vue的构造函数,开发人员可以通过new关键字创建Vue构造函数的实例对象(MVVM中VM层)。
代码:
<!--引入Vue三方库-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!--创建一个DOM元素-->
<div id="app"></div>
<script>
// 通过new关键字实例化一个Vue对象
// Vue 构造函数接收配置对象
new Vue({
el: '#app' // el 指定页面中DOM元素,Vue就会以这个DOM为挂载对象
})
</script>
Vue实例配置选项
在实例化Vue对象时,构造函数Vue可以接受一个Object作为实例配置对象,该对象中接受多个配置选项用来实现不同的效果。
el: 提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。挂载完毕后当前DOM内部渲染将会由当前Vue实例对象所管理与控制
new Vue({
el: '#app'
})
data: (属性)存放当前Vue实例对象数据的配置。Vue 将会递归的将 data 的 property 转换为 getter/setter,从而让 data 的 property 能够响应数据变化。
对象必须是纯粹的对象 (含有零个或多个的 key/value 对): 浏览器 API 创建的原生对象,原型上的 property 会被忽略。大概来说,data 应该只能是数据,不推荐观察拥有状态行为的对象。
注意: data 对象自身可以被实例对象的$data属性所访问,并且在所有data直接子属性都可以被实例对象直接访问和修改。
var vm = new Vue({
el: '#app',
data: {
name: '小明',
age: 18,
detail: {
tel: 138121345678,
eMail: 'helloworld@163.com',
address: '广州'
}
},
mounted() {
console.log(this.age) // 18 实例对象可以直接访问
}
})
vm.$data // data对象
vm.age //18 等价于 vm.$data.age
vm.detail.tel //138121345678 vm.$data.detail.tel
// 实例对象的方法可以直接修改
// 并且vm的data数据改变会引起页面的自动更新(数据的双向绑定)
vm.age++
vm.detail.tel = 13193870000
数据绑定技术
概念: Vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的,Vue在初始化使用Object.defineProperty
递归的将data的属性添加一个getter/setter (监听器Observer),用来劫持并监听所有属性(Vue 解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器即调用当前属性getter方法的元素就是订阅者)。Vue会把所有当前data的订阅者存放在一个dep名单中,如果有变动的,就通过dep名单通知所有订阅者。从而更新视图。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rKoWROOz-1664414257975)(./imgs/01.png)]
模板语法
双大括号文本差值
概念: Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:vue使用 {{js表达式}} (双大括号语法)
将实例中的属性或者其他js表达式插值绑定到模板的任何文本节点中
语法:
<div id="app">
内部都由Vue实例对象管理
<p>姓名:{{name}}</p>
<p>年龄:{{age}}</p>
<p>状态:{{age >= 18 ? '已成年':'未成年'}}</p>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
name: '小明',
age: 18
}
})
</script>
注意:
双大括号语法会将内部的表达式以纯文本的形式插入到对应节点内部。这种模式可以预防xss攻击(注入攻击将一段恶意脚本发送到html页面从而获取用户的cookie信息)
<div id="app">
<p>{{script}}</p>
// 这里渲染的结果是'<div>hello world<div>'的文本节点,而不是一个dom元素
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
script: '<div>hello world<div>'
}
})
</script>
指令语法
概念: Vue为开发者提供很多执行应用在虚拟DOM标签上以实现不同的效功能效果
语法: 指令=“js表达式”
- 指令 v-html
介绍: 可以将文本以html形式插入到指定节点内部而不用向上面一样插入一个纯文本。
注意: 永远不要把这个方法暴露给用户
<div id="app">
<p>{{script}}</p> // 纯文本
<div v-html="script"></div> // h3dom元素
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
script: '<h3>hello world</h3>'
}
})
</script>
- 指令 v-once
介绍: 一次性地插值,当数据改变时,插值处的内容不会更新
<div id="app">
<p v-once="str"></p> // v-once插入的文本内容不会更新
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
str: 'hello world'
}
})
setTimeout(() => vm.str = 'hello Vue !')
</script>
v-bind属性差值
概念: 使用指令 v-bind:属性 =“js表达式” 形式将实例中的data或者其他js表达式插值绑定到标签的任何属性节点中
语法:
<div id="app">
已成年<input type="radio" v-bind:checked="age >= 18"/>
未成年<input type="radio" v-bind:checked="age < 18"/>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
age: 18,
}
})
</script>
注意:
- v-bind:指令可以简写成一个冒号 “:”
<div id="app">
已成年<input type="radio" :checked="age >= 18"/>
未成年<input type="radio" :checked="age < 18"/>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
age: 18,
}
})
</script>
- v-bind 支持动态属性
<div id="app">
<a v-bind:[attrname]="link"> 百度 </a>
<!-- <a src="http://www.baidu.com"> 百度 </a> -->
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
attrname: 'src',
link: 'http://www.baidu.com'
}
})
</script>
注意:
- 动态参数预期会求出一个字符串,异常情况下值为 null。这个特殊的 null 值可以被显性地用于移除绑定。任何其它非字符串类型的值都将会触发一个警告。
- 空格和引号,放在 HTML attribute 名里是无效的
<a v-bind:['foo' + bar]="value"> ... </a> // 错误
v-bind绑定class
1. 对象语法
我们观察下面代码,我们给每一段歌词元素都绑定了一个class类。内部js表达式逻辑就是当currentIndex 与歌词下标匹配时,歌词元素的class值就会变成active,否则为空。但是我们发现,代码过于繁琐。Vue针对class提供对象语法来简化下面的代码
<div id="app">
<p v-bind:class="currentIndex === 0 ? 'active': ''">
第一段歌词 0
</p>
<p v-bind:class="currentIndex === 1 ? 'active': ''">
第二段歌词 1
</p>
<p v-bind:class="currentIndex === 2 ? 'active': ''">
第三段歌词 2
</p>
<p v-bind:class="currentIndex === 3 ? 'active': ''">
第四段歌词 3
</p>
<p v-bind:class="currentIndex === 4 ? 'active': ''">
第五段歌词 4
</p>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
currentIndex: 3
}
})
</script>
v-bind绑定的class支持对象写法: v-bind:class = {class名: 判别式}
。当判别式为真时,保留该类名否则删除该类名
上面的代码可以使用class对象语法简写为
<div id="app">
<p v-bind:class="{active: currentIndex === 0}">第一段歌词 0</p>
<p v-bind:class="{active: currentIndex === 1}">第二段歌词 1</p>
<p v-bind:class="{active: currentIndex === 2}">第三段歌词 2</p>
<p v-bind:class="{active: currentIndex === 3}">第四段歌词 3</p>
<p v-bind:class="{active: currentIndex === 4}">第五段歌词 4</p>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
currentIndex: 3
}
})
</script>
2. 数组语法
概念: Vue还支持v-bind:class=数组
写法,数组中的每一项都可以是js表达式,并且数组中可以包含class对象写法
<div id="app">
<p v-bind:class="currentIndex === 0 ? 'active lry ' + className: 'lry '+ className">
第一段歌词 0
</p>
<p v-bind:class="[{active: currentIndex === 1}, 'lry', className]">
第二段歌词 1
</p>
<p v-bind:class="[{active: currentIndex === 2}, 'lry', className]">
第三段歌词 2
</p>
<p v-bind:class="[{active: currentIndex === 3}, 'lry', className]">
第四段歌词 3
</p>
<p v-bind:class="[{active: currentIndex === 4}, 'lry', className]">
第五段歌词 4
</p>
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
currentIndex: 3,
className: 'test'
}
})
</script>
注意:
- class 的数组语法,对象语法中的数组或对象都可以存放data中绑定给class (data中不要使用this)
- 一个dom元素中可以最对同时拥有 一个绑定的class属性和一个普通class属性
<p v-bind:class="[{active: currentIndex === 3}, 'lry', className]"> 第四段歌词 3 </p> <p class="lry" v-bind:class="[{active: currentIndex === 4}, className]"> 第五段歌词 4 </p>
v-bind绑定style
1. 对象语法
概念: v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名。
<div id="app">
<!-- 短横线命名CSS样式需要加引号-->
<p v-bind:style="{color,backgroundColor,'font-size': '18px'}">
我是一段文本
</p>
</div>
<script>
new Vue({
el: '#app',
data: {
color: 'blue',
backgroundColor: 'orange'
}
})
</script>
2. 数组语法
概念: v-bind:style 的数组语法可以将多个样式对象应用到同一个元素上
<div id="app">
<p v-bind:style="[defaultStyle,{color,backgroundColor,fontSize: '18px'}]">
我是一段文本
</p>
</div>
<script>
new Vue({
el: '#app',
data: {
color: 'blue',
backgroundColor: 'orange',
defaultStyle: {
fontWeight: 700,
border: '1px solid #ccc'
}
}
})
</script>
3.v-bind:style的多重值
概念: style 绑定中的样式属性可以提供一个包含多个值的数组,常用于提供多个带前缀的值。
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染 display: flex。
4.v-bind:style自动添加前缀
概念: 当v-bind:style 使用需要添加浏览器引擎前缀的 CSS property 时,如 transform,Vue.js 会自动侦测并添加相应的前缀。
<div :style="{ transform: 'rotate(-45deg)' }">Hello</div>
事件处理
概念: 在vue中可以给DOM元素通过 v-on 指令,绑定事件处理逻辑。
语法: v-on:事件名="js表达式"
<div id="app">
每次点击h2标签 count都会加一
<h2 v-on:click="count++">{{count}}</h2>
</div>
<script>
new Vue({
el: '#app',
data: {
count: 17
}
})
</script>
注意: 不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined。
扩展: v-on: 指令可以简写为 @
符号
<div id="app">
<h2 v-on:click="count++">{{count}}</h2>
<button @click="count--">minus</button>
</div>
<script>
new Vue({
el: '#app',
data: {
count: 17
}
})
</script>
data: {
count: 17
}
})
```
注意: 不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined。
扩展: v-on: 指令可以简写为 @
符号
<div id="app">
<h2 v-on:click="count++">{{count}}</h2>
<button @click="count--">minus</button>
</div>
<script>
new Vue({
el: '#app',
data: {
count: 17
}
})
</script>