Vue.js 教程
详细教程请看官网:
https://cn.vuejs.org/v2/guide/syntax.html#%E6%8C%87%E4%BB%A4
目录
文章目录
1. 创建一个Vue实例:
每一个Vue应用都是通过Vue 函数创建一个新的Vue实例开始的:
var vm = new Vue({
//选项
})
2. 数据与方法
除了数据属性,Vue实例还暴露了一些有用的实例 属性与方法。它们都有前缀 $ ,以便与用户定义的属性区分开来 ,例如:$watch({ })
<div id="app3">
<!-- 声明一个a变量 -->
{{a}}
</div>
<script type="text/javascript">
var data = { a: 1 };
var vm = new Vue({
el : "#app3",
data : data,
//注意两个data不是一个值
});
//$watch.a 记录a变化前后的值(控制台记录)语法如下
//data.a 和 vm.a 用来给a重新赋值
vm.$watch('a', function(newVal, oldVal){
console.log(newVal,oldVal);
})
vm.$data.a = "test...."
</script>
3. 实例生命周期钩子(函数)
-
需要写在 newVue({}) 内,以属性的方式声明 ,这个属性是一个函数, 在系统运行的每一个阶段,系统会自动调用已经声明的这个生命周期函数。
-
生命周期函数不能使用箭头函数
<script type="text/javascript">
var vm = new Vue({
el : "#app4",
data : {
msg: "hi vue",
},
/*在实例初始化之后,数据观测(data observer) 和
evevt/watcher 事件配置之前被调用(在页面被创建之间调用)。*/
beforeCreate:function(){
console.log('beforeCreate');
},
/*在实例创建完成后被立即调用。
在这一步,实例已完成以下的配置:数据观测(data observer)
属性和方法的运算,watch/event 事件回调。
然而,挂载阶段还没开始,$el 属性目前不可见。*/
created :function(){
console.log('created');
},
//在挂载开始之前被调用:相关的渲染函数首次被调用
beforeMount : function(){
console.log('beforeMount');
},
//el 被新创建的 vm.$el 替换,挂载成功
mounted : function(){
console.log('mounted');
},
//数据更新时调用
beforeUpdate : function(){
console.log('beforeUpdate');
},
//组件 DOM 已经更新,组件更新完毕
updated : function(){
console.log('updated');
}
});
setTimeout(function(){
vm.msg = "change ......";
}, 3000);
</script>
4. 模板语法 - 插值
Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式德地将 DOM 绑定至底层Vue 实例的数据。所有Vue.js的模板都是合法的 HTML ,所以能被遵循规范的浏览器和 HTML 解析器解析。
在底层的实现上,Vue 将模板变异成虚拟 DOM 渲染函数。结合响应系统, Vue能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。
- 插值
**# **文本
- 数据绑定最常见的形式就是使用 “Mustache” 语法(双大括号)的文本插值:
<span>Message:{{ mssg }}</span>
-
Mustache标签将会被替代为对应数据对象上 msg 属性的值, 无论何时, 绑定的数据对象上 msg 属性发生了改变,插值处的内容都会更新。
-
通过使用 v-once 指令,也能执行一次性地插值,当数据改变时,插值处的内容不会更新,但请留心这会影响到该节点上的其他数据绑定:
<span v-once>这个将不会改变: {{ msg }}</span>
# 原始HTML
双大括号会将数据解释为普通文本,而非 HTML 代码,为了输出真正的 HTML,你需要使用 v-html 指令:
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
这个 span 的内容将会被替换成为属性值 rawHtml, 直接作为 HTML 一一会忽略解析属性值中的数据绑定,注意,你不能使用 v-html 来复合局部模板,因为 Vue 不是基于字符串的模板引擎。
# 特性
Mustache 语法不能作用在 HTML 特性上, 遇到这种情况应该使用 v-bind 指令:
<div v-bind:id="dynamicId"></div>
对于布尔特性(他们只要存在就意味值为 true ),v-bind 工作起来略有不同,在这个例子中:
<button v-bind:disabled="isButtonDisabled">Button</button>
如果 isButtonDisabled 的值是 null ,undefined 或 false , 则 disabled 特性甚至不会被包含在渲染出来的 元素中。
# 使用 JavaScript 表达式
迄今为止,在我们的模板中,我们一直都只绑定简单的属性键值,但实际上,对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
<!-- message.split('') 将内容拆分成一个数组, .reverse() 反序排列, join('') 再将数组结合成一个字符串-->
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>
这些表达式会在所属Vue实例的数据作用域下作为 JavaScript被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}
<!-- 流控制也不会生效请使用三元表达式 -->
{{ if (ok) { return message } }}
5. 模板语法 - 指令
指令(Directives)是带有 v- 前缀的特殊特性。指令特性的值预期是单个 JavaScript
表达式 (v-for 是例外情况)。指令的职责是,当表达式的值改变时,将其产生的连带影响。响应式地作用于 DOM 。
<p v-if="seen">现在你看到我了</p>
<!-- seen 是否会被渲染,取决于data 的属性 true/false-->
这里 v-if 指令将根据表达式 seen 的值得真假来插入/移除
元素。
# 参数
一些指令能够接收一个“参数”,在指令名称之后以冒号表示。例如 v-bind 指令可以用于响应式地更新 HTML 特性:
<a v-bind:href="url">...</a>
在这里 href
是参数(用于绑定超链接),告知 v-bind
指令将该元素的 href
attribute 与表达式 url
的值绑定。
另一个例子是 v-cn 指令,它用于监听 DOM 事件:
<a v-cn:click="doSomething">...</a>
在这里参数是监听的事件名,我们也会更详细的讨论事件处理。
# 修饰符
修饰符(modifier)是以半角句号 . 指明特殊后缀,用于指出一个指令应该以特殊方式绑定。例如 .prevent 修饰符告诉 v-on 指令对于触发的事件调用 event .preventDefault() :
<form v-on:submit.prevent="onSubmit">...</form>
6. Class 与 Style 绑定
操作元素的 class 列表和内联样式是数据绑定的一个常见需求、因为他们都是attribute, 所以我们可以用 v-bind 处理它们: 只需要通过表达式计算出字符串结果即可。由于字符串拼接麻烦且易错。因此,在将 v-bind
用于 class
和 style
时,Vue.js 做了专门的增强。表达式结果的类型除了字符串之外,还可以是对象或数组。
绑定 HTMLClass
# 对象语法
我们可以传给 v-bind:class
一个对象,以动态地切换 class:
<div v-bind:class="{ active: isActive }"></div>
上面的语法表示 active
这个 class 存在与否将取决于数据 property isActive
的 truthiness。
你可以在对象中传入更多字段来动态切换多个 class。此外,v-bind:class
指令也可以与普通的 class attribute 共存。当有如下模板:
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>
和如下 data:
data: {
isActive: true,
hasError: false
}
结果渲染为:
<div class="static active"></div>
绑定内联样式
# 对象语法
v-bind:style
的对象语法十分直观——看着非常像 CSS,但其实是一个 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-bind:style
的数组语法可以将多个样式对象应用到同一个元素上:
<div v-bind:style="[baseStyles, overridingStyles]"></div>
7. 条件渲染
v-if
v-if
指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。
<h1 v-if="awesome">Vue is awesome!</h1>
也可以用 v-else
添加一个“else 块”:
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
# v-else-if
v-else-if
,顾名思义,充当v-if
的“else-if 块”,可以连续使用:
<div id="app">
<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 type="text/javascript">
var vm = new Vue({
el : "#app",
data : {
type : "B",
//为 type 设置变量,就会被渲染出变量的值
ok : true
//通过设置true和false 展示和隐藏ok的值
}
});
</script>
<style type="text/css">
v-show
另一个用于根据条件展示元素的选项是 v-show
指令。用法大致一样:
<h1 v-show="ok">Hello!</h1>
不同的是带有 v-show
的元素始终会被渲染并保留在 DOM 中。v-show
只是简单地切换元素的 CSS property display
。
注意,v-show
不支持 <template>
元素,也不支持 v-else
。
v-if VS v-show
-
v-if
是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。 -
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。 -
相比之下,
v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。 -
一般来说,
v-if
有更高的切换开销,而v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show
较好;如果在运行时条件很少改变,则使用v-if
较好。
8. 列表渲染
用 v-for 把一个数组对应为一组元素
我们可以用 v-for
指令基于一个数组来渲染一个列表。v-for
指令需要使用 item in items
形式的特殊语法,其中 items
是源数据数组,而 item
则是被迭代的数组元素的别名。
<div id="app">
<ul>
<li v-for="item,index in items" :key="index">
<!-- index 索引 渲染出的结果items加上索引-->
{{index}}{{ item.message }}
</li>
</ul>
<ul>
<li v-for="value, key in object">
<!-- key 键 显示出object对应的键 -->
{{key}} : {{ value }}
</li>
</ul>
</div>
<script type="text/javascript">
var vm = new Vue({
el : "#app",
data : {
items : [
{ message: 'Foo' },
{ message: 'Bar' }
],
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
}
});
</script>
9. 事件处理
# 监听事件
可以用 v-on 指令监听 DOM 事件,并在出发时运行一些 JavaScript 代码。
<div id="app">
<div id="example-1">
<button v-on:click="counter += 1"> 数值 : {{ counter }} </button><br />
<!-- 有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法: -->
<button v-on:dblclick="greet('abc', $event)">Greet</button>
</div>
</div>
<script type="text/javascript">
var vm = new Vue({
el : "#app",
data : {
counter: 0,
name : "vue"
},
methods:{
greet : function (str, e) {
alert(str);
//输出 event
console.log(e);
}
}
});
</script>
<style type="text/css">
</style>
# 事件修饰符
.stop
.prevent
.capture
.self
.once
.passive
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
<!-- 修饰符可以串联 -->
<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:click.prevent.self
会阻止所有的点击,而 v-on:click.self.prevent
只会阻止对元素自身的点击。
10. 表单输入绑定
# 基础用法
可以用 v-model
指令在表单 <input>
、<textarea>
及 <select>
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。
v-model
会忽略所有表单元素的value
、checked
、selected
attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的data
选项中声明初始值。
v-model
在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
-
text 和 textarea 元素使用
value
property 和input
事件; -
checkbox 和 radio 使用
checked
property 和change
事件; -
select 字段将
value
作为 prop 并将change
作为事件。
# 文本
<div id="app">
<div id="example-1">
<input v-model="message" placeholder="edit me">
<!-- v-model绑定message事件,placeholder 提示字体-->
<p>Message is: {{ message }}</p>
<!-- 双向绑定 在后面输出message -->
</div>
</div>
<script type="text/javascript">
var vm = new Vue({
el : "#app",
data : {
message : "",
//默认值为空 在文本框里输入内容 该内容同样会显示在Message is:后面
},
});
</script>
效果:
# 多行文本
<textarea v-model="message2" placeholder="add multiple lines"></textarea>
<p style="white-space: pre-line;">{{ message2 }}</p>
<br />
var vm = new Vue({
el : "#app",
message2 :"",
//结果依然默认为空 在文本框里输入内容 该内容同样会显示在文本框下面
});
结果:
# 复选框
单个复选框,绑定到布尔值:
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
checked : true,
结果:
多个复选框,绑定到同一个数组:
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
new Vue({
el: "#app",
data: {
checkedNames : ['Jack', 'John'],
//默认选择俩
},
});
结果:
# 单选按钮
<div style="margin-top:20px;">
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
</div>
new Vue({
el: "#app",
data: {
picked : "Two"
//默认选择Two
},
});
结果:
# 选择框
单选时
<div id="example-2">
<select v-model="selected">
<option disabled value ="" >请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
new Vue({
el: "#app",
data: {
selected : ''
//默认选择空
},
});
结果:
如果
v-model
表达式的初始值未能匹配任何选项,<select>
元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像上面这样提供一个值为空的禁用选项。(请选择)
# 多选时(绑定到一个数组):
<div>
<select v-model="hhhhh" multiple style="width: 50px;">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>hhhhh : {{ hhhhh }}</span>
</div>
new Vue({
el: "#app",
data: {
hhhhh : []
//默认选择空
},
});
结果:鼠标上下拉取可多选
# 提交按钮
<button type="button" @click="submit">提交</button>
var vm = new Vue({
el : "#app",
data : {
message : "test",
message2 :"hi",
checked : true,
checkedNames : ['Jack', 'John'],
picked : "Two",
selected : '',
hhhhh : []
},
methods: {
submit : function () {
console.log(this.message);
var postObj = {
msg1 : this.message,
msg2 : this.message2,
checkval : this.checkedNames,
picked : this.picked,
selected : this.selected,
hhhhh : this.hhhhh
};
console.log(postObj);
}
}
});
# 用 v-for 渲染的动态选项:
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
new Vue({
el: '...',
data: {
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
]
}
})
结果:
11.组件基础
# 基本示例
这是一个 Vue 组件的示例:
<div id="app">
<!-- 组件是可以复用的,可以将组件进行任意次数的复用
当点击按钮时,每个组件都会各自独立维护它的 count
因为没用一次组件,就会有一个它的新实例被创建-->
<button-counter title="title1 : "></button-counter>
<button-counter title="title2 : "></button-counter>
</div>
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
结果:
# data必须是一个函数
当我们定义这个 组件时,它的 data 并不是直接提供一个对象:
data:{
count: 0
}
取而代之的是, 一个组件的 data 选项必须是一个函数 ,因此每个实例可以维护一份被返回对象的独立的拷贝:
data: function (){
return {
count: 0
}
}
如果 Vue 没有这条规则,点击一个按钮就可能会影响到其他所有实例:
比如:
# 组件的组织
通常一个应用会以一颗潜逃的组件树的形式来组织:
例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其他的像导航链接、博文之类的组件。
为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。有两种组件的注册类型: 全剧组件和局部组件。至此,我们的组件都只是通过 Vue.component 全局注册的:
Vue.component({
// ... options ...
})
全局注册的组件可以用在其被注册之后的任何(通过 new Vue)新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。
# 组件的事件监听
<div id="app">
//4. 在组件的父级通过事件绑定去接收到emit函数所触发的事件
<button-counter title="title1 : " @clicknow="clicknow">
<h2>hi...h2</h2>
</button-counter>
<button-counter title="title2 : "></button-counter>
</div>
<script type="text/javascript">
Vue.component('button-counter', {
props: ['title'],
data: function () {
return {
count: 0
}
},
// 1.将click事件绑定成一个ckickfun函数事件 下面methods声明该函数,
// 2.通过this对象的$emit方法去触发该事件,第一个值是 事件名称,第二个值是可携带的参数
// 6.<slot>标签 作用:插槽,可以在button之间随意插入内容
template: '<div><h1>hi...</h1><button v-on:click="clickfun">{{title}} You clicked me {{ count }} times.</button><slot></slot></div>',
methods:{
clickfun : function () {
this.count ++;
this.$emit('clicknow', this.count);
}
}
})
var vm = new Vue({
el : "#app",
data : {
},
// 5. 最后在页面上依然用methods属性来声明clicknow方法 接收且打印参数
methods:{
clicknow : function (e) {
console.log(e);
}
}
});
</script>
12.组件注册
# 组件名
在注册一个组件的时候,我们始终需要给它一个名字。比如在全局注册的时候我们已经看到了:
Vue.component('my-component-name', { /* ... */ })
该组件名就是 Vue.component 的第一个参数。
你给予组件的名字可能依赖于你打算拿它来做什么。当直接在 DOM 中使用一个组件(而不是在字符串模板或单文件组件)的时候,我们强烈推荐遵循 W3C 规范中的自定义组件名(字母全小写且必须包含一个连字符)。避免和当前以及未来的 HTML 元素相冲突。
# 组件名大小写
定义组件名的方式有两种:
-
使用 kebab-case 短横线的方式
Vue.component('my-component-name', { /* ... */ })
当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如:
<my-component-name>
。 -
使用 PascalCase 驼峰命名法
Vue.component('MyComponentName', { /* ... */ })
# 全局注册
到目前为止,我们只用过 Vue.component
来创建组件:
这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (
new Vue
) 的模板中。比如:
Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ })
new Vue({ el: '#app' })
<div id="app">
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
</div>
在所有子组件中也是如此,也就是说这三个组件在各自内部也都可以相互使用。
# 局部注册
全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。
在这些情况下,你可以通过一个普通的 JavaScript 对象来定义组件:
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
然后在 components
选项中定义你想要使用的组件:
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
对于 components
对象中的每个 property 来说,其 property 名就是自定义元素的名字,其 property 值就是这个组件的选项对象。
t` 来创建组件:
这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (
new Vue
) 的模板中。比如:
Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ })
new Vue({ el: '#app' })
<div id="app">
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
</div>
在所有子组件中也是如此,也就是说这三个组件在各自内部也都可以相互使用。
# 局部注册
全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。
在这些情况下,你可以通过一个普通的 JavaScript 对象来定义组件:
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
然后在 components
选项中定义你想要使用的组件:
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
对于 components
对象中的每个 property 来说,其 property 名就是自定义元素的名字,其 property 值就是这个组件的选项对象。