优点
1、体积小;
2、运行效率高-因为是基于虚拟DOM,一种可以预先通过JavaScript进行各种计算,把最终的DOM操作计算出来并优化的技术,由于这个DOM操作属于/预处理/操作,并没有真实的操作DOM,所以叫做虚拟DOM;
3、双向数据绑定
让开发者不用再去操作DOM对象,把更多的精力投入到业务逻辑上;
4、生态丰富
UI框架,组件丰富;
声明式渲染
Vue.js的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进DOM的系统;
//视图部分
<div id="app">
{{ message }}
</div>
//脚本部分
<script>
var app = new Vue({
el:'#app',
data:{
message:'Hello Vue!'
}
})
</script>
输出:Hello Vue!
此时:数据data已经和dom(HTML文档类型)已经建立了关联,所有东西都是响应式的,el=element,此时相当于选中id 为app的div元素,而标签内的双大括号表示绑定的内容,此时只需要在data中改变message的数值,元素内的内容也会相应的改变。
创建一个Vue实例
每个Vue应用都是通过用Vue函数创建一个新的Vue实例开始的:
var vm = new Vue({
//选项对象 vm=viewModel,这个变量表示Vue实例
})
使用这些选项来创建你想要的行为,一个Vue应用由一个通过new Vue创建的根Vue实例,以及可选的嵌套的、可复用的组件树组成,所有的Vue组件都是Vue实例,并且接受相同的选项对象(一些根实例特有的选项除外)。
数据与方法
当一个Vue实例被创建时,它将data对象中的所有的属性(property)加入到Vue的响应式系统中。当这些属性(property)的值发生改变时,视图讲会产生“响应式”,即匹配更新为新的值。
//数据对象
var data = { a:1 }
//该对象北加入到一个Vue实例中
var vm = new Vue({
el :"#app",
data:data
})
//获得这个实例上的属性(property)
//返回源数据中对应的字段
vm.a == data.a // => true
//设置属性(property)也会影响到原始数据
vm.a = 2
data.a // => 2
// ...反之亦然
data.a = 3
vm.a // => 3
当这些数据改变时,视图会进新重新渲染。只有当实例被创建时(new vue) data中存在 的属性才是响应式的。
当加入一个data中不存在的b属性时,例如:
vm.b = 'hi'
那么对b的改动将不会触发如何视图的更新。
如果想设置一些初始值,晚些时再利用,可以如此书写:
data:{
newTodoTest:'',
visitCount:0,
hideCompletedTodos:false,
todos:[],
error:null
}
Object.freeze()
追踪属性变化的例外情况,使用Object.freeze(),这会阻断内容和数据的响应式变化;
var obj = {
foo:'bar'
}
Object.freeze(obj)
new Vue({
el:'#app',
data:obj
})
<div id="app">
<p></p>
<!-- 这里的'foo'不会更新! -->
<button v-on:click="foo = 'baz'">Change it</button>
</div>
实例 property 与方法
除了 数据property ,Vue实例还暴露了一些有用的 实例property与方法。特点是前缀$,以便与用户定义的property区分开来,例如:
var data = { a:1 }
var vm = new Vue({
el:'#example',
data:data
})
//$data
vm.$data === data // => true
vm.$el === document.getElementById('example') // => true
//$watch(实例方法)
vm.$watch('a',function(newValue,oldValue){
//这个回调将在'vm.a'改变后调用
})
生命周期
每个Vue实例在被创建时都要经历一些列的初始化过程–例如,需要设置数据监听、编译模板、将实例挂载到DOM并在数据变化时更新DOM等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在 不同阶段 添加自己的代码的机会。
例如 created 钩子可以用来在一个实例被创建之后执行代码:
new Vue({
data:{
a:1
},
created:function(){
//'this'指向vm实例
console.log('a is:' + this.a)
}
})
// => "a is:1
生命周期图示:
模板语法
Vue.js使用了基于HTML的模板语法,允许开发者声明式地将DOM绑定至底层Vue实例的数据。所有Vue.js的模板都是合法的HTML,所以能被遵循规范的浏览器和HTML解析器解析。
在底层的实现上,Vue将模板编译成虚拟DOM渲染函数。结合响应系统,Vue能够智能地计算出最少需要重新渲染多少组件,并把DOM操作次数减到最少。
插值
1、文本
数据绑定最常见的形式就是使用“Mustache”语法(双大括号)的文本插值:
<span>Message:{{ msg }}</span>
mustache标签将会被替代为对应数据对象(data)上 msg property的数值。无论何时,绑定的数据对象上 msg property 发生了改变,插值处的内容都会更新。
<span v-once>这个将不会改变:{{ msg }}</span>
通过使用v-once指令,能执行一次性地插值,当数据改变时,插值处的内容不会更新。
原始HTML
因为双大括号会将数据解释为普通文本,而非HTML代码。目标是为了输出标签内的HTML内容(非直接输出文本,而是输出根据HTML标签编译的相应内容)。
<p v-html="rawHtml"></p>
<script>
var vm = new Vue({
el:"#app",
data:{
msg:"hi vue",
rawHtml:'<span style="color:red">this is should be red</span>'
}
});
</script>
此时的p标签中,不会出现this is should be red,而是显示,this is should be red;
特性
Mustache 语法不能作用在HTML 属性上,遇到这种情况应该使用v-bind指令:
<div v-bind:id="dynamicId"></div>
对于布尔属性:
<button v-bind:disabled="isButtonDisabled">Button</button>
如果isButtonDisabled的值是null、undefined or false,则 disabled attribute甚至 不会被包含在 渲染出来的元素中。
使用JavaScript表达式
Vue.js 提供了完全的 JavaScript 表达式支持
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>
指令
指令(Directives)是带有v-前缀的特殊attribute。指令attribute的值预期是单个JavaScript表达式(v-for 是例外)。指令的职责是,当表达式的值改变时,将产生的连带影响,响应式地作用于DOM。
<p v-if="seen"> now </p>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
seen:true or false
}
});
</script>
这里,v-if指令将根据表达式seen的值真假来渲染插入/移除
元素。
参数
一些指令能够接收一个“参数”,在指令名称之后以冒号表示。例如, v-bind指令 可以响应式地更新HTMLattribute:
<a v-bind:href="url">...</a>
这里的href是参数,告知v-bind指令将该元素的href这个attribute与表达式url的数值绑定。
例子二:
<a v-on:click="doSomething">...</a>
在这里参数是鉴定的事件名,指令是v-on指令。
修饰符
修饰符(modifier)是以半角句号.指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent修饰符告诉v-on指令对于触发的事件调用event.preventDefault():
<form v-on:submit.prevent="onSubmit">...</form>
绑定HTML Class
操作元素的class列表和内联样式和内联样式是数据绑定的一个常见需求。因为它们都是attribute,所以我们可以用v-bind处理:通过表达式计算出字符串结果。
对象语法:
传给v-bind:class一个对象,以动态切换class:
<div v-bind:class="{active:isActive}"></div>
语法表示 active 这个 class 存在与否将取决于数据 property isActive 的 truthiness。
<div class="static" v-bind:class="{active:isActive,'text-danger':hasError}">
//这个就叫做内联定义
</div>
这段代码说明在对象中传入更多字段,能够动态切换多个class。v-bind:class指令也可以与普通的class attribute共存。
data部分:
data:{
isActive:true,
hasError:false
}
渲染结果:
<div class="static active"></div>
当isActive或者hasError变化时,true or false,class列表将相应的更新。例如,如果hasError的数值为true,class列表将变为"static active text-danger"。
绑定的数据对象不必内联定义在模板里:
<div v-bind:class="classObject"></div>
//没有进行内联定义,只写了对象名称
data:{
classObject:{
active:true,
'text-danger':false
}
}
列外,举例:绑定一个返回对象的计算属性
<div v-bind:class="classObject"></div>
data:{
isActive:true,
error:null
},
computed:{
classObject:function(){
return{
active:this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
绑定内联样式
对象语法:
v-bind:style对象语法是一个JavaScript对象。
CSS property名可以用驼峰式(camelCase)或者短横线分割(kebab-case)
<div v-bind:style="{color:activeColor,fontSize:fontSize+'px'}"></div>
data:{
activeColor:'red',
fontSize:30
}
直接绑定到一个 样式对象 会让模板更清晰:
<div v-bind:style="styleObject"></div>
data:{
styleObject:{
color:'red',
fontSize:'13px'
}
}
条件渲染
v-if指令用于条件性地渲染一块内容,内容会在指令的表达式返回truthy值时被渲染,返回ture,执行or渲染。
<h1 v-if="awesome">Vue is awesome!</h1>
也能用v-else添加一个"else块”:
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else> oh </h1>
例:
<div>
<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>
<h1 v-show="ok">Hello!</h1>
</div>
<script>
var vm = new Vue({
el:"#app",
data:{
type:"B"
//切换为A/B/C 将渲染不同的内容
ok:false
//此时v-show不进行渲染
}
});
</script>
列表渲染
1、用v-for把一个 数组 对应为一组元素;
2、v-for指令需要使用item in items形式的特殊语法,其中items是源数据数组,而item则是被迭代的被显示的数组元素的别名;
3、使用v-for指令对内容进行迭代时,会获得item对象内容。
<ul id="example-1">
<li v-for="item in items">
//每一次迭代都会得到属性对应的数值
{{ item.message }}
</li>
<li v-for="value in object">
//每一次迭代都会得到对应属性值
{{ value }}
</li>
</ul>
<script>
var vm = new Vue({
el:'#example-1',
data:{
items:[
{ message:'Foo' },
{ message:'Bar' }
],
object:{
//键值对,key:value
title:'How to do lists in Vue',
author:'Jane Doe',
publishedAt:'2016-04-10'
}
}
});
</script>
维护状态
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。这个类似 Vue 1.x 的 track-by="$index"。
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出
为了给Vue一个提示,以便它能 跟踪每个节点的身份 ,从而 重用和重新排序 现有元素,你需要为每项提供一个唯一的 key attribute:
<div v-for="item in items" v-bind:key="item.id">
content
</div>
事件处理
监听事件,用v-on监听DOM事件,在触发事件时运行一些JavaScript代码。
<div id="example-1">
<button v-on:click="counter +=1">Add 1</button>
<p>The button above has been clicked {{ counter }} times.</p>
//绑定了事件的Add 1每被敲击一次,就会在p元素的counter中显示被增加后的数值
</div>
var example1 = new Vue({
el:'#example-1',
data:{
counter:0
}
})
表单输入绑定
使用v-model指令在表单、 and 元素上
## 使用v-model指令在表单<input>、<textarea> and <select>元素上
创建双向数据绑定。v-model负责监听
用户的输入事件以更新数据,
并对一些极端场景进行一些特殊的处理。
v-model 会忽略所有表单元素的 value、checked、selected
attribute 的初始值,而总是将Vue 实例的数据
作为数据来源。通过data选项,声明初始值。
v-model在内部为不同的输入元素使用不同的property
并抛出不同的事件:
- text and textarea元素使用
value property and input 事件;
- checkbox and radio use the checked
property and change事件;
- select 字段将value作为prop并将change作为事件;
组件基础(重复使用的vue实例)
通过将重复功能封装为组件,达到快捷便捷开发的目的,通过component函数来创建一个组件,参数一是组件的名称,第二个参数以对象的形式去描述一个组件,包括数据或模板内容。
Vue.component('button-counter',{
data:function(){
return{
count:0
}
},
template:'<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
组件时可复用的Vue实例,且带有一个名字:
本例中的就是一个组件,组件能够通过自定义元素来使用:
<div id="components-demo">
<button-counter></button-counter>
//button-counter就是一个自定义元素,附:元素由一个开始的标签和结束的bai标签组成,用来包含某些内容
</div>
组件的特点:
因为组件是可复用的Vue实例,所以它们与new Vue接收相同的选项。例如data、computed、watch、methods以及生命周期钩子等。仅有的例外是像el这样根实例特有的选项。
props:更像是一个绑定在属性位置上,方便修改模板内容,而不是属性,说不定目的是绑定在属性位置上进行个性化修改的。
组件注册
1、组件名,在注册一个组件时起的名字,例如全局注册时第一个参数:
Vue.component('my-component-name',{/*...*/})
命名需要遵循W3C规范中的 自定义组件名 ,目的是避免和当前以及未来的HTML元素相冲突。
2、组件名规范之大小写
定义组件名的方式有两种:
使用kebab-case
Vue.component('my-component-name',{/*...*/})
当使用kebab-case(短横线分隔命名)定义一个组件时,必须在引用这个自定义元素时使用kebab-case,例如
使用PascalCase
Vue.component('MyComponentName',{/*...*/})
当使用pascalCase(首字母大写命名)定义一个组件,能够使用两种命名方法。 and 。胆,直接在DOM(非字符串模板)中使用时,只有kebab-case有效。
全局注册
全局注册使用Vue.component方法来创建组件:
Vue.component('my-componen-name',{
//...选项...
})
局部注册
使用普通的JavaScript对象来定义组件:
var ComponentA = { /*...*/ }
var ComponentB = { /*...*/ }
var ComponentC = { /*...*/ }
然后在components选项中定义组件:
new Vue({
el:'#app',
components:{
'component-a':ComponentA,
'component-b':ComponentB
}
})
对于 components 对象中的每个 property 来说,其 property 名就是自定义元素的名字,其 property 值就是这个组件的选项对象。
问题:局部注册的组件在其子组件中不可用。如果想让ComponentA在ComponentB中使用,应当这样写:
var ComponentA = { /*...*/ }
var ComponentB = {
components:{
'component-a':ComponentA
},
//...
}
单文件组件
全局组件是使用Vue.component来定义全局组件,再使用new Vue({ el: ‘#container’ })在每个页面内指定一个容器元素,这样的定义方式只适合当JavaScript仅被用来加强特定的视图。如果项目完全由JavaScript驱动,将会出现以下缺点:
1、全局定义 (Global definitions) 强制要求每个 component 中的命名不得重复;
2、字符串模板 (String templates) 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的 \;
3、不支持 CSS (No CSS support) 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏;
4、没有构建步骤 (No build step) 限制只能使用 HTML 和 ES5 JavaScript,而不能使用预处理器,如 Pug (formerly Jade) 和 Babel;
以上的问题可以通过文件名为.vue的single-file components(单文件组件)解决,并使用webpack or Browserify等构建工具。
单文件组件示例
这是一个文件名为Hello.vue的实例,通过单文件组件,能够获得,完整的语法高亮,CommonJS模块,组件作用域的CSS。
在创建单文件组件时,可以使用预处理器来构建组件,预处理器能够实现组件简洁化和更多的功能。
单文件组件在创建前,需要安装相应的使用环境。
<template>
<p>{{ greeting }}world!</p>
</template>
<script>
module.exports = {
data: function(){
return{
greeting:'Hello'
}
}
}
</script>
<style scoped>
p{
font-size:2em;
text-align:center;
}
</style>
‘