1、Vue 实例
1.1 构造器
每个 Vue.js 应用的起步都是通过构造函数 Vue
创建一个 Vue 的根实例:
var test = new Vue({
// 选项
})
在实例化 Vue 时,需要传入一个选项对象,它可以包含数据、模板、挂载元素、方法、生命周期钩子等选项。全部的选项可以在 API 文档中查看。https://cn.vuejs.org/v2/api/
可以扩展 Vue
构造器,从而用预定义选项创建可复用的组件构造器:
var MyComponent = Vue.extend({
// 扩展选项
})
// 所有的 `MyComponent` 实例都将以预定义的扩展选项被创建
var myComponentInstance = new MyComponent()
尽管可以命令式地创建扩展实例,不过在多数情况下将组件构造器注册为一个自定义元素,然后声明式地用在模板中。其实所有的 Vue.js 组件其实都是被扩展的 Vue 实例。
1.2 属性与方法
每个 Vue 实例都会代理其 data
对象里所有的属性:
var data = { a: 1 }
var vm = new Vue({
data: data
})
vm.a === data.a // -> true
// 设置属性也会影响到原始数据
vm.a = 2
data.a // -> 2
// ... 反之亦然
data.a = 3
vm.a // -> 3
注意只有这些被代理的属性是响应的。如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。
除了这些数据属性,Vue 实例暴露了一些有用的实例属性与方法。这些属性与方法都有前缀 $
,以便与代理的数据属性区分。例如:
var data = { a: 1 }
var vm = new Vue({
el: '#example',
data: data
})
vm.$data === data // -> true
vm.$el === document.getElementById('example') // -> true
// $watch 是一个实例方法
vm.$watch('a', function (newVal, oldVal) {
// 这个回调将在 `vm.a` 改变后调用
})
1.3 实例的生命周期
Vue 实例在创建时有一系列初始化步骤——例如,它需要建立数据观察,编译模板,创建必要的数据绑定。在此过程中,它也将调用一些生命周期钩子,给自定义逻辑提供运行机会。例如 created
钩子在实例创建后调用:
var vm = new Vue({
data: {
a: 1
},
created: function () {
// `this` 指向 vm 实例
console.log('a is: ' + this.a)
}
})
// -> "a is: 1"
也有一些其它的钩子,在实例生命周期的不同阶段调用,如 compiled
、 ready
、destroyed
。钩子的 this
指向调用它的 Vue 实例。
1.4 生命周期图示
2、数据绑定
2.1 插值
数据绑定最基础的形式是文本插值,使用 “Mustache” 语法(双大括号):
<span>Message: {{msg}}</span>
Mustache 标签会被相应数据对象的 msg
属性的值替换。每当这个属性变化时它也会更新。
2.2 绑定表达式
放在 Mustache 标签内的文本称为绑定表达式。
在 Vue.js 中,一段绑定表达式由一个简单的 JavaScript 表达式和可选的一个或多个过滤器构成。
2.2.1 JavaScript 表达式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绑定表达式</title>
</head>
<body>
<div id="app">
<p>number+1: {{number+1}}</p>
<p>ok 值为 {{ok}} 时输出的结果:{{ok?'YES':'NO'}}</p>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app',
data:{
number:12,
ok:true
}
})
</script>
</body>
</html>
结果:
2.2.2 过滤器
过滤器是对即将显示的数据做进一步的筛选处理,然后进行显示,值得注意的是过滤器并没有改变原来的数据,只是在原数据的基础上产生新的数据。
Vue.js 允许在表达式后添加可选的“过滤器 (Filter) ”,以“管道符”指示:
{{ message | capitalize }}
这里我们将表达式 message
的值“管输(pipe)”到 capitalize
过滤器,返回大写化的值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>过滤器</title>
</head>
<body>
<div id="app">
<p>原始数据:{{msg}}</p>
<p>过滤器后的数据:{{msg|capitalize}}</p>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app',
data:{
msg:'hello'
},
//局部过滤器
filters:{
'capitalize':function(value){
//将信息转成大写
return value.toUpperCase()
}
}
})
</script>
</body>
</html>
结果:
3、指令
- 指令 (Directives) 是特殊的带有前缀
v-
的特性。 - 指令的值限定为绑定表达式,因此上面提到的 JavaScript 表达式及过滤器规则在这里也适用。
- 指令的职责就是当其表达式的值改变时把某些特殊的行为应用到 DOM 上。
3.1 条件渲染
3.1.1 v-if
v-if
指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 true 值的时候被渲染。
v-if
指令将根据表达式 ok值的真假删除/插入 <p>
元素:
<p v-if="ok">Love!</p>
也可以用 v-else
添加一个“else 块”:
<p v-if="ok">Love!</p1>
<p v-else>Hate</p>
v-else
元素必须紧跟在带 v-if
或者 v-else-if
的元素的后面,否则它将不会被识别。
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-if</title>
</head>
<body>
<div id="app">
<p v-if="ok">表达式返回为{{ok}},所以输出:Love!</p1>
<p v-else>表达式返回为{{ok}},所以输出:Hate!</p>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app',
data:{
ok:false
}
})
</script>
</body>
</html>
结果:
v-else-if
,顾名思义,充当 v-if
的“else-if 块”,可以连续使用:
<div v-if="type === 'A'">A</div>
<div v-else-if="type === 'B'">B</div>
<div v-else-if="type === 'C'">C</div>
<div v-else>Not A/B/C</div>
类似于 v-else
,v-else-if
也必须紧跟在带 v-if
或者 v-else-if
的元素之后。
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-if</title>
</head>
<body>
<div id="app">
<div v-if="type === 'A'">type的值为{{type}},所以输出为:A</div>
<div v-else-if="type === 'B'">type的值为{{type}},所以输出为:B</div>
<div v-else-if="type === 'C'">type的值为{{type}},所以输出为:C</div>
<div v-else>type的值为{{type}},所以输出为:Not A/B/C</div>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app',
data:{
type:true
}
})
</script>
</body>
</html>
结果:
3.1.2 v-show
另一个用于根据条件展示元素的选项是 v-show
指令。用法大致一样:
<h1 v-show="ok">Hello!</h1>
不同的是带有 v-show
的元素始终会被渲染并保留在 DOM 中。v-show
只是简单地切换元素的 CSS 属性 display
。
3.1.3 v-if vs v-show
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
3.2 列表渲染
3.2.1 在 v-for 里使用数组
可以使用 v-for
指令基于一个数组渲染一个列表。这个指令使用特殊的语法,形式为 item in items
,items
是数据数组,item
是当前数组元素的别名:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-for</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="item in items">
{{ item.name }}
</li>
</ul>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app',
data:{
items: [
{ name: '李四' },
{ name: '张三' }
]
}
})
</script>
</body>
</html>
结果:
在 v-for
块中,我们可以访问所有父作用域的属性。v-for
还支持一个可选的第二个参数,即当前项的索引。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-for父作用域</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item,index) in items">
{{parentMessage}}{{index}}:{{ item.name }}
</li>
</ul>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app',
data:{
parentMessage:'序号',
items: [
{ name: '李四' },
{ name: '张三' }
]
}
})
</script>
</body>
</html>
结果:
也可以用 of
替代 in
作为分隔符,因为它更接近 JavaScript 迭代器的语法:
<div v-for="item of items"></div>
3.2.2 在 v-for 里使用对象
用 v-for
来遍历一个对象的属性。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-for在对象中使用</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="message in book">
{{message}}
</li>
</ul>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app',
data:{
books:{
title:'一生最爱纳兰词',
author:'聂小晴',
owner:'S_numb'
}
}
})
</script>
</body>
</html>
结果:
你也可以提供第二个的参数为 property 名称 (也就是键名):
<ul>
<li v-for="(message,name) in book">
{{name}}: {{message}}
</li>
</ul>
结果:
还可以用第三个参数作为索引:
<ul>
<li v-for="(message,name,index) in book">
<!-- 因为不想序号从0开始所以加1 -->
{{index+1}}- {{name}}: {{message}}
</li>
</ul>
结果:
3.2.3 在 v-for 里使用值的范围
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-for在对象中使用</title>
</head>
<body>
<div id="app">
<span v-for="n in 10">{{n}} </span>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app'
})
</script>
</body>
</html>
结果:
3.3 事件处理
3.3.1 监听事件
可以用 v-on
指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。
<!-- 完整语法 -->
<a v-on:click="doSomething"></a>
<!-- 缩写 -->
<a @click="doSomething"></a>
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>监听事件</title>
</head>
<body>
<div id="app">
<button v-on:click="counter+=1">加1</button>
<p>这个按钮已经按了{{counter}}次</p>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app',
data:{
counter:0
}
})
</script>
</body>
</html>
结果:
3.3.2 事件处理方法
然而许多事件处理逻辑会更为复杂,所以直接把 JavaScript 代码写在 v-on
指令中是不可行的。因此 v-on
还可以接收一个需要调用的方法名称。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件处理</title>
</head>
<body>
<div id="app">
<button v-on:click="clickMe">你点我一下试试</button>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app',
data:{
name:'有本事你再点我一下试试'
},
methods:{
clickMe:function(){
// `this` 在方法里指向当前 Vue 实例
alert('你竟然敢点我!'+ this.name +'!')
}
}
})
</script>
</body>
</html>
结果:
3.3.3 内联处理器中的方法
除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件处理</title>
</head>
<body>
<div id="app">
<button v-on:click="say('hi')">Hi</button>
<button v-on:click="say('hello')">Hello</button>
<button v-on:click="say('nice to meet you')">Nice to meet you</button>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app',
methods:{
say:function(msg){
alert(msg)
}
}
})
</script>
</body>
</html>
结果:
3.3.4 事件监听的优点
-
扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
-
因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
-
当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。
3.4 绑定
3.4.1 单向绑定 v-bind
v-bind
指令用于响应地更新 HTML 特性。
<!-- 完整语法 -->
<a v-bind:href="url"></a>
<!-- 缩写 -->
<a :href="url"></a>
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>单向绑定</title>
</head>
<body>
<div id="app">
<h1 v-bind:title="msg">时间</h1>
<hr>
<p>若想看当前时间,请将鼠标放在上面的时间标题上!</p>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app',
data:{
msg:'时间'+ new Date().toLocaleString()
}
})
</script>
</body>
</html>
结果:
3.4.2 双向绑定 v-model
双向绑定也称表单输入绑定;可以用 v-model
指令在表单 、
及 `` 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
v-model
会忽略所有表单元素的value
、checked
、selected
attribute 的初始值而总是将 Vue 实例的数据作为数据来源。所以应该通过 JavaScript 在组件的data
选项中声明初始值。
v-model
在内部为不同的输入元素使用不同的属性并抛出不同的事件:
- text 和 textarea 元素使用
value
属性和input
事件; - checkbox 和 radio 使用
checked
属性和change
事件; - select 字段将
value
作为 prop 并将change
作为事件。
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>双向绑定</title>
</head>
<body>
<div id="app">
<p>
你改变此输入框的值,不会影响初始值:
<input type="text" v-bind:value="msg">
</p>
<p>
你改变此输入框的值,会影响初始值:
<input type="text" v-model="msg">
</p>
</div>
<script src="./lib/vue.js"></script>
<script>
var test = new Vue({
el:'#app',
data:{
msg:'初始值'
}
})
</script>
</body>
</html>
结果:
4、路由
4.1 官方路由
对于大多数单页面应用,都推荐使用官方支持的 vue-router 库。
详细细节: https://router.vuejs.org/
4.2 简单的路由
路由:页面链接跳转!(单页面)
4.2.1 新建一个项目,并导入所需依赖:
4.2.2 新建一个 lib 文件夹,将依赖导入,方便调用:
4.2.3 编写程序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<h1>鬼剑士转职</h1>
<p>
<router-link to="/">首页</router-link>
</p>
<p>
<router-link to="/first">阿修罗</router-link>
<router-link to="/second">剑魂</router-link>
<router-link to="/third">狂战士</router-link>
<router-link to="/fourth">鬼泣</router-link>
</p>
<hr>
<!-- 显示 view -->
<router-view></router-view>
</div>
<script src="./lib/vue.js"></script>
<script src="./lib/vue-router.js"></script>
<script>
//1、定义路由的组件
const welcom = {template:'<div>点击链接查看鬼剑士转职名称</div>'}
const first = {template:'<div><ul><li>一转:阿修罗</li><li>觉醒:大暗黑天</li><li>二转:天帝</li></ul></div>'}
const second = {template:'<div><ul><li>一转:剑魂</li><li>觉醒:剑圣</li><li>二转:剑神</li></ul></div>'}
const third = {template:'<div><ul><li>一转:狂战士</li><li>觉醒:狱血魔神</li><li>二转:帝血弑天</li></ul></div>'}
const fourth = {template:'<div><ul><li>一转:鬼泣</li><li>觉醒:弑魂</li><li>二转:黑暗君主</li></ul></div>'}
// 2、定义路由
const routes = [
{path:'/',redirect:'/welcom'},
{path:'/welcom',component:welcom},
{path:'/first',component:first},
{path:'/second',component:second},
{path:'/third',component:third},
{path:'/fourth',component:fourth}
]
//3、创建 router 实例
const router = new VueRouter({
routes:routes
})
//4、挂载路由
new Vue({
el:'#app',
router
})
</script>
</body>
</html>
4.2.4 测试结果
首页:
阿修罗:
剑魂:
狂战士:
鬼泣: