参考网站:
1 Vue.js 及其实例
Vue.js是一个JavaScript MVVM{(Model-View-ViewModel)库,Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定。
ViewModel是Vue.js的核心,它是一个Vue
实例。使用Vue的过程就是定义MVVM的各个模块的过程:
- 定义View
- 定义Model
- 定义ViewModel(Vue实例),用于连接Model与View
通常一个 Vue 应用由一个通过 new Vue
创建的根 Vue 实例,以及可选的嵌套的、可复用的组件树组成。
具体实现如下:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<!-- 导入vue.js -->
<script type="text/javascript" src="vue2.1.8.js"></script>
</head>
<body>
<!-- Vue实例是作用于某一个HTML元素上的,这个元素可以是HTML的body元素,也可以是指定了id的某个元素 -->
<div id="app">
<!-- 编写view -->
<p v-text="message"></p>
</div>
</body>
<script type="text/javascript">
/* 编写Model,是一个对象 */
var model = {message:'abc'}
/* 编写ViewModel */
var vm = new Vue({
el:'#app',//el属性指向View
data:model//data属性指向Model,常直接使用对象表示
});
alert(vm.message);//每个 Vue 实例都会代理其 data 对象里所有的属性
</script>
</html>
1.1 实例数据 data
当一个 Vue 实例被创建时,它向 Vue 的响应式系统中加入了其 data
对象中能找到的所有的属性。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
值得注意的是只有当实例被创建时 data
中存在的属性是响应式的。也就是说如果你添加一个新的属性,像:
vm.b = 'hi'
那么对 b 的改动将不会触发任何视图的更新。
1.2 计算属性 computed
和观察者 watch
虽然 Vue.js 都提供了完全的 JavaScript 表达式支持,模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。
所以,对于任何复杂逻辑,你都应当使用 计算属性。
1.2.1 计算属性缓存 vs 方法属性 methods
当然,通过在表达式中调用方法 methods
也可以达到同样的效果,不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。
即多次访问计算属性会立即返回之前的计算结果,而不必像是用方法属性那样再次执行函数。
这也同样意味着下面的计算属性将不再更新,因为 Date.now()
不是响应式依赖:
computed: {
now: function () {
return Date.now()
}
}
1.2.2 计算属性 vs 侦听属性 watch
使用侦听属性 watch
同样可以达到使用计算属性的效果,只不过使用的代码量会加大,而且也不容易理解,如:
<div id="demo">{{ fullName }}</div>
// 使用 watch 属性
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
1.2.3 计算属性的 setter
计算属性默认只有 getter
,不过在需要时你也可以提供一个 setter
:
// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// ...
现在再运行 vm.fullName = 'John Doe'
时,setter
会被调用,vm.firstName
和 vm.lastName
也会相应地被更新。
1.2.4 侦查器 watch
同样的上述代码的实现功能使用 watch
侦查属性来做,就能更好的理解,代码量也会更少
1.3 实例的生命周期
每个 Vue 实例在被创建之前都要经过一系列的初始化过程。例如需要设置数据监听、编译模板、挂载实例到 DOM、在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做 生命周期钩子 的函数,给予用户机会在一些特定的场景下添加他们自己的代码。
以下是来自官网的实例的生命周期介绍图,钩子函数的 this
指向 Vue 实例:
2 Vue.js的常用指令
Vue指令是以“v-”开头,作用于HTML元素,指令会为绑定目标添加一些特殊行为。
对于所有的数据绑定, Vue.js 都提供了完全的 JavaScript 表达式支持 , 实际上,指令属性的值 预期是单个 JavaScript 表达式 (v-for
是例外)情况如:
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>
这些表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}
<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}
2.1 关于插入文本或HTML
2.1.1 v-text
, v-html
, v-once
指令
Vue 文本插值常用一对双花括号 {{ }}
表示,但在有些情况使用花括号会有冲突(如应用使用了 Jinja2 模板),此时可以使用v-text
指令,使用方法如下述代码。 v-html
指令用于插入HTML代码:
<div id="app" v-html="message">
</div>
<script type="text/javascript">
var vm = new vue({
el:'#app',
data:{message:'<p>123</p>'}
})
</script>
此时绑定的数据,会随着 message
属性的变化而变化,如果想要执行一次性地插值,当数据改变时,插值处的内容不会更新。可以使用 v-once
指令:
<span v-once>这个将不会改变: {{ msg }}</span>
2.1.2 v-if
指令与v-show
指令
v-if
指令会根据表达式的真假来决定删除或插入元素,它的语法是v-if="expression"
,其中expression
返回布尔值
<div id="app">
<p v-if="yes">123</p>
<!-- Vue.js 都提供了完全的 JavaScript 表达式支持 -->
<p v-if="10>9">123</p>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{yes:true}
})
</script>
v-show
指令与v-if
指令类似,都是根据其expression
的布尔值来执行相应的动作,区别在于v-show
指令仅仅改变的是HTML元素的display
属性。
2.1.3 v-else
指令
v-else
指令必须要跟在v-if
或v-show
元素后面,否则自身并不能识别:
<div id="app">
<p v-if="9>12">123</p>
<p v-else>456</p>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
})
</script>
2.1.4 v-for
指令
v-for
指令基于一个数组渲染,循环可以为数组,对象属性以及整数。语法为v-for="item in items"
- 数组(使用数组,还可以 支持一个可选参数作为当前项的索引):
<div id='app'>
<ul>
<li v-for="item in items" v-text="item.name"></li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{
items:[{name:1},{name:2},{name:3},{name:4},{name:5}]
}
})
</script>
- 对象属性(循环对象,如果设定了循环出三个参数,那么依次为对象 属性,键名,索引):
<div id='app'>
<ul>
<li v-for="value,item,index in items">{{value}} {{item}} {{index}}</li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{
items:{name:'Seiei',sex:'man',age:'18'}
}
})
</script>
- 整数:
<div id='app'>
<ul>
<!-- 其中由0开始,直到10(包括10) -->
<li v-for="value in 10">{{value}}</li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#app'
})
</script>
2.2 关于插入元素属性及事件属性
2.2.1 v-bind
指令
使用
v-bind
指令还可以缩写,v-bind:
缩写成:
,如v-bind:class
可以缩写成:class
。
v-bind
指令用于绑定HTML元素的属性,语法为:v-bind:argument="expression"
:
<style type="text/css">
.red{color: red}
</style>
<div id='app'>
<p v-bind:class="class1">123</p>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{
class1:'red'
}
})
</script>
2.2.1.1 绑定 Class
v-bind
在处理 class
和 style
时, 专门增强了它。表达式的结果类型除了字符串之外,还可以是对象或数组。
注意:对象语法 引用的classname是真类名,并不是Model中的变量
a. 对象语法
<style type="text/css">
.red{color: red}
</style>
<div id='app'>
<!--
注意:view中引用的classname是真类名,并不是Model中的变量
-->
<p v-bind:class="{red:isred}">123</p>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{
isred:false
}
})
</script>
b. 数组语法
语法v-bind:class="[classname1,classname2]"
,此时若想像传入对象那样动态切换类名,则可以使用 三元表达式,或直接引入一个 对象语法
<style type="text/css">
.red{color: red}
.blue{background-color: blue}
</style>
<div id='app'>
<!-- View中类名使用的Model变量 -->
<p v-bind:class="[isActive ? activeClass : '',class2,{active: isactive}]">123</p>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{class1:'red',class2:'blue',isactive:true}
})
</script>
2.2.1.1 绑定 Style
a. 对象语法
绑定 style
时,建议只使用 对象语法,CSS 属性名可以用 驼峰式 (camelCase) 或 短横线分隔 (kebab-case,记得用单引号括起来) 来命名,如:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
activeColor: 'red',
fontSize: 30
}
- 当然直接绑定到一个 样式对象 通常更好,这会让模板更清晰
- Vue.js 会自动侦测并添加 浏览器引擎前缀 的 CSS 属性
2.2.2 v-on
指令
v-on
指令用于绑定事件属性,如:
<div id='app'>
<button v-on:click="func">123</button>
<!-- 可以传入参数 -->
<button v-on:click="func2('seiei')">456</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{message:'helloworld'},
<!-- 函数要放在Vue实例的methods属性中(注意后缀s) -->
methods:{
<!-- 当中的this指向的是vm -->
func:function(){alert(this.message)},
func2:function(x){alert(x)}
}
})
</script>
有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event
把它传入方法
2.2.3 修饰符
修饰符 (Modifiers) 是以半角句号 .
指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。
.stop
.prevent
.capture
.self
.once
<!-- 阻止单击事件继续传播 -->
<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
也能缩写,如v-on:click
可以缩写成@click
,且在建立Vue对象下不能使用普通语法来绑定事件
2.3 表单指令v-model
v-model
指令在表单控件元素上创建View与Model的双向数据绑定。
v-model
会忽略所有表单元素的value
、checked
、selected
特性的初始值。因为它会选择 Vue 实例数据来作为具体的值。你应该通过 JavaScript 在组件的 data 选项中声明初始值。
因此,<select>
元素就会以”未选中”的状态渲染。在 iOS 中,这会使用户无法选择第一个选项,解决方法
<div id='app'>
<p>{{message}}</p>
<input type="text" name="num" v-model="message" placeholder="123">
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{message:''}//注意,view与model是通过Vue实例(viewmodel)来链接的
})
</script>
同样的当input
类型为checkbox
,radio
时,取得的是其设定的value
值。而当复选框如果是一个为逻辑值,如果是多个则可以绑定到同一个数组:
<div id='app'>
<p>{{message}}</p>
<label for="python"></label><input id="python" type="checkbox" name="num" v-model="message" value="python">
<label for="javascript"></label><input id="javascript" type="checkbox" name="num" v-model="message" value="javascript">
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#app',
data:{message:[]}
})
</script>
2.3.1 值绑定
如果想绑定 value
到 Vue 实例的一个动态属性上,可以使用 v-bind:value
实现
2.3.2 修饰符
.number
:自动将用户的输入值转为Number
类型(如果原值的转换结果为 NaN 则返回原值).trim
:自动过滤用户输入的首尾空格,<input v-model.trim="msg">
2.4 组件component
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树
2.4.1 使用组件
2.4.1.1 全局注册
要注册一个全局组件,可以使用 Vue.component(tagName, options)
,组件在注册之后,便可以作为自定义元素在一个实例的模板中使用,注意确保在初始化根实例之前注册组件。
2.4.1.2 局部注册
你不必把每个组件都注册到全局。你可以通过某个 Vue 实例/组件的实例选项 components
注册仅在其作用域中可用的组件,如:
var Child = {
template: '<div>A custom component!</div>'
}
new Vue({
// ...
components: {
// <my-component> 将只在父组件模板中可用
'my-component': Child
}
})
2.4.1.3 DOM 模板解析注意事项
因为 Vue 只有在浏览器解析、规范化模板之后才能获取其内容。尤其要注意,像 <ul>
、<ol>
、<table>
、<select>
这样的元素里允许包含的元素有限制,而另一些像 <option>
这样的元素只能出现在某些特定元素的内部。
在自定义组件中使用这些受限制的元素时会导致一些问题,例如:
<table>
<my-row>...</my-row>
</table>
自定义组件 <my-row>
会被当作无效的内容,因此会导致错误的渲染结果。变通的方案是使用特殊的 is 特性:
<table>
<tr is="my-row"></tr>
</table>
2.4.2 组件的通讯(prop
)
在 Vue 中,父子组件的关系可以总结为 prop
向下传递,事件向上传递。父组件通过 prop
给子组件下发数据,子组件通过事件给父组件发送消息。
组件实例的作用域是孤立的。这意味着不能在子组件的模板内直接引用父组件的数据。父组件的数据需要通过 prop
才能下发到子组件中。
注意:
- 在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组,尽管在子组件内部定义了一个局部变量保存它,但改变它还是会影响父组件的状态。
- HTML 特性是不区分大小写的。所以,当使用的不是字符串模板时,驼峰式命名 的
prop
需要转换为相对应的 短横线分隔式命名
2.4.2.1 动态 prop
与绑定到任何普通的 HTML 特性相类似,我们可以用 v-bind
来动态地将 prop
绑定到父组件的数据。每当父组件的数据变化时,该变化也会传导给子组件。
如果你想把一个对象的所有属性作为 prop
进行传递,可以使用不带任何参数的 v-bind
(即用 v-bind
而不是 v-bind:prop-name
)。例如,已知一个 todo
对象:
todo: {
text: 'Learn Vue',
isComplete: false
}
然后:
<todo-item v-bind="todo"></todo-item>
将等价于:
<todo-item v-bind:text="todo.text" v-bind:is-complete="todo.isComplete">
</todo-item>
2.4.2.2 prop
验证
我们可以为组件的 prop 指定验证规则。如果传入的数据不符合要求,Vue 会发出警告,要指定验证规则,需要用 对象的形式 来定义 prop
,而不能用字符串数组,对象选项有:
type
:数据类型,可以为数组表示可能的多个类型default
:表示传递数据的默认值,数组/对象的默认值应当由一个工厂函数返回required
:布尔值,表示是否必须传入validator
:自定义验证函数
Vue.component('example', {
props: {
// 基础类型检测 (`null` 指允许任何类型)
propA: Number,
// 可能是多种类型
propB: [String, Number],
// 必传且是字符串
propC: {
type: String,
required: true
},
// 数值且有默认值
propD: {
type: Number,
default: 100
},
// 数组/对象的默认值应当由一个工厂函数返回
propE: {
type: Object,
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
return value > 10
}
}
}
})