Vue.js入门学习
1、什么是Vue.js
-
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架
-
Vue 被设计为可以自底向上逐层应用
-
Vue 的核心库只关注视图层,方便与第三方库或既有项目整合
2、Vue.js的作用
- 通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件
3、安装
<!--下载文件后引入-->
<script src="文件路径"></script>
<!--在线引入引入-->
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
4、简单了解
4.1、声明式渲染
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统
helloworld
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{ message }}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'hello vue!'
}
})
</script>
</body>
</html>
现在数据和 DOM 已经被建立了关联,所有东西都是响应式的,在控制台可以修改app.message的值,就可以看到更新
指令:指令带有前缀 v-
,以表示它们是 Vue 提供的特殊属性。,它们会在渲染的 DOM 上应用特殊的响应式行为
鼠标悬停
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app-2">
<span v-bind:title = "message">
鼠标悬停
</span>
</div>
<script>
var app2 = new Vue({
el: '#app-2',
data: {
message: "页面加载于"+new Date().toLocaleString()
}
})
</script>
</body>
</html>
条件与循环
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app-3">
<p v-if="seen">现在你看到我了</p>
</div>
<div id="app-4">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</div>
<script>
var app3 = new Vue({
el: "#app-3",
data: {
seen: true
}
})
var app4 = new Vue({
el: '#app-4',
data: {
todos: [
{text: '学习JavaScript'},
{text: '学习vue'},
{text: '整个牛项目'}
]
}
})
</script>
</body>
</html>
处理用户输入
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app-5">
<p>{{message}}</p>
<button v-on:click="reverseMessage">反转消息</button>
</div>
<script>
var app5 = new Vue({
el: '#app-5',
data:{
message: 'hello vue!'
},
methods:{
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})
</script>
</body>
</html>
双向绑定:实现表单输入和应用状态之间的双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id = "app-6">
<p>{{message}}</p>
<input v-model="message">
</div>
<script>
var app6 = new Vue({
el: '#app-6',
data: {
message:'hello Vue!'
}
})
</script>
</body>
</html>
4.2、组件化应用构建
组件系统:使用小型、独立和通常可复用的组件构建大型应用。几乎任意类型的应用界面都可以抽象为一个组件树。
- 在 Vue 里,一个组件本质上是一个拥有预定义选项的一个 Vue 实例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app-7">
<ol>
<!--
现在我们为每个 todo-item 提供 todo 对象
todo 对象是变量,即其内容可以是动态的。
我们也需要为每个组件提供一个“key”,稍后再
作详细解释。
-->
<todo-item
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id"
></todo-item>
</ol>
</div>
<script>
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
var app7 = new Vue({
el: '#app-7',
data: {
groceryList: [
{ id: 0, text: '蔬菜' },
{ id: 1, text: '奶酪' },
{ id: 2, text: '随便其它什么人吃的东西' }
]
}
})
</script>
</body>
</html>
5、实例
创建一个Vue实例
-
每个 Vue 应用都是通过用
Vue
函数创建一个新的 Vue 实例开始的 -
一个 Vue 应用由一个通过
new Vue
创建的根 Vue 实例var vm = new Vue({ // 选项 })
数据与方法
当一个 Vue 实例被创建时,它将 data
对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
-
修改不存在data中的属性是不会修改视图的,如果预先知道需要用的属性可以预先初始化
-
Object.freeze():阻止修改现有的属性
-
$ 符号,用来区分用户定义的属性
vm.$data === data // => true vm.$el === document.getElementById('example') // => true // $watch 是一个实例方法 vm.$watch('a', function (newValue, oldValue) {//可以查看修改后的新值和旧值 // 这个回调将在 `vm.a` 改变后调用 })
生命周期钩子
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
生命周期
6、模板语法
- 所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。
- 在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。
6.1、插值
文本
<span>Message: {{ msg }}</span><!--将data中的msg插入-->
<span v-once>这个将不会改变: {{ msg }}</span><!--一次性插值-->
html
双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html
<p>Using mustaches: {{ rawHtml }}</p><!--普通输出,会把html标签当作普通文本输出-->
<p>Using v-html directive: <span v-html="rawHtml"></span></p><!--让html标签能被识别-->
html属性
<div v-bind:id="dynamicId"></div><!--通过v-bind:指令可以实现对html属性的操作-->
js表达式
支持js表达式
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>
6.2、指令
指令 (Directives) 是带有 v-
前缀的特殊属性
<p v-if="seen">现在你看到我了</p>
<!--
v-if 指令将根据表达式 seen 的值的真假来插入/移除 <p> 元素
-->
参数
一些指令能够接收一个“参数”,在指令名称之后以冒号表示
<a v-bind:href="url">...</a>
<!--
在这里 href 是参数,告知 v-bind 指令将该元素的 href 属性 与表达式 url 的值绑定
-->
<a v-on:click="doSomething">...</a><!--用于监听 DOM 事件-->
动态参数
从 2.6.0 开始,可以用方括号括起来的 JavaScript 表达式作为一个指令的参数
<a v-bind:[attributeName]="url"> ... </a>
<!--
这里的 attributeName 会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果你的 Vue 实例有一个 data property attributeName,其值为 "href",那么这个绑定将等价于 v-bind:href。
-->
对动态参数的值的约束
- 动态参数预期会求出一个字符串,异常情况下值为
null
。这个特殊的null
值可以被显性地用于移除绑定。任何其它非字符串类型的值都将会触发一个警告。
对动态参数表达式的约束
-
动态参数表达式有一些语法约束,因为某些字符,如空格和引号,放在 HTML 属性名里是无效的
<!-- 这会触发一个编译警告 --> <a v-bind:['foo' + bar]="value"> ... </a>
缩写
v-bind缩写
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>
v-on缩写
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>
7、计算属性和监听器
7.1、计算属性
基础例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
<script>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
</script>
</body>
</html>
- 声明了一个计算属性
reversedMessage
。提供的函数将用作 propertyvm.reversedMessage
的 getter 函数 - Vue 知道
vm.reversedMessage
依赖于vm.message
,因此当vm.message
发生改变时,所有依赖vm.reversedMessage
的绑定也会更新 - 以声明的方式创建了这种依赖关系
计算属性VS方法
- 计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要
message
还没有发生改变,多次访问reversedMessage
计算属性会立即返回之前的计算结果 - 相比之下,每当触发重新渲染时,调用方法将总会再次执行函数
计算属性VS侦听属性
侦听属性:Vue 提供的一种来观察和响应 Vue 实例上的数据变动更通用的方式
当你有一些数据需要随着其它数据变动而变动时,你很容易滥用
通常更好的做法是使用计算属性,而不是命令式的 watch
回调
计算属性的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 也会相应地被更新
7.2、侦听器
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch
选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
8、Class与Style绑定
8.1、绑定HTML Class
对象语法
//单个class
<div v-bind:class="{ active: isActive }"></div>
<script>
data: {
isActive: true,//通过这个来动态的切换class
}
</script>
//多个class
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>
<script>
data: {
isActive: true,
hasError: false
}
</script>
- 可以使用计算属性
数组语法
<div v-bind:class="[activeClass, errorClass]"></div>
<script>
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
</script>
<!--三元表达式-->
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
- 中括号里可以使用三元表达式
8.2、绑定内联样式
对象语法
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
<script>
data: {
activeColor: 'red',
fontSize: 30
}
</script>
数组语法
<div v-bind:style="[baseStyles, overridingStyles]"></div>
<script>
data: {
baseStyles: {
color: 'red',
fontSize: '13px'
},
overridingStyles: {
color: 'red',
fontSize: '13px'
}
}
</script>
9、渲染
9.1、条件渲染(if)
-
v-if:用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。
<h1 v-if="awesome">Vue is awesome!</h1>
-
v-else:
v-else
指令用来表示v-if
的“else 块”<h1 v-if="awesome">Vue is awesome!</h1> <h1 v-else>Oh no 😢</h1>
-
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>
-
用
key
管理可复用的元素:Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处<template v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username"> </template> <template v-else> <label>Email</label> <input placeholder="Enter your email address"> </template> <!-- 上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,<input> 不会被替换掉——仅仅是替换了它的 placeholder。 --> <template v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username" key="username-input"> </template> <template v-else> <label>Email</label> <input placeholder="Enter your email address" key="email-input"> </template> <!-- Vue 提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key属性 即可 -->
-
v-show:根据条件展示元素
<h1 v-show="ok">Hello!</h1>
v-show
的元素始终会被渲染并保留在 DOM 中v-show
只是简单地切换元素的 CSS propertydisplay
。
9.2、列表渲染(for)
-
用 v-for 把一个数组对应为一组元素
<ul id="example-1"> <li v-for="item in items" :key="item.message"> {{ item.message }} </li> </ul> <script> var example1 = new Vue({ el: '#example-1', data: { items: [ { message: 'Foo' }, { message: 'Bar' } ] } }) </script>
-
在 v-for 里使用对象
<ul id="v-for-object" class="demo"> <li v-for="value in object"> {{ value }} </li> </ul> <script> new Vue({ el: '#v-for-object', data: { object: { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } } }) </script>
-
维护状态
当 Vue 正在更新使用
v-for
渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。- 适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
-
数组更新检测
变更方法
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
替换数组
变更方法,顾名思义,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如 filter()
、concat()
和 slice()
。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组
-
显示过滤/排序后的结果
有时,我们想要显示一个数组经过过滤或排序后的版本,而不实际变更或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数组
<li v-for="n in evenNumbers">{{ n }}</li> <script> data: { numbers: [ 1, 2, 3, 4, 5 ] }, computed: { evenNumbers: function () { return this.numbers.filter(function (number) { return number % 2 === 0 }) } } </script>
-
v-for可以指定循环次数
<div> <span v-for="n in 10">{{ n }} </span> </div>
10、事件处理
10.1、监听事件
可以用 v-on
指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id = "example-1">
<button v-on:click="counter += 1">
add 1
</button>
<p>{{counter}}</p>
</div>
<script>
var expample1 = new Vue({
el: '#example-1',
data: {
counter: 0
}
})
</script>
</body>
</html>
10.2、事件处理方法
v-on
还可以接收一个需要调用的方法名称
<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id = "example-2">
<button v-on:click="greet">greet</button>
</div>
<script>
var example2 = new Vue({
el: '#example-2',
data: {
name:'vue.js'
},
methods: {
greet: function (event) {
alert("hello"+this.name+'!');
if (event){
alert(event.target.tagName);
}
}
}
})
</script>
</body>
</html>
10.3、事件修饰符
Vue.js 为 v-on
提供了事件修饰符,修饰符是由点开头的指令后缀来表示的
.stop
.prevent
.capture
.self
.once
.passive
<!-- 阻止单击事件继续传播 -->
<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>
10.4、按键修饰符
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on
在监听键盘事件时添加按键修饰符
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
<!--处理函数只会在 $event.key 等于 PageDown 时被调用-->
<input v-on:keyup.page-down="onPageDown">
10.5、系统修饰符
<!-- Alt + C -->
<input v-on:keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div v-on:click.ctrl="doSomething">Do something</div>
<!--.exact修饰符-->
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button v-on:click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button v-on:click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button v-on:click.exact="onClick">A</button>
<!--鼠标按钮修饰符-->
.left
.right
.middle
11、表单输入绑定
v-model
指令在表单 input、textarea 及select 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。
注意:
v-model
会忽略所有表单元素的value
、checked
、selected
attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的data
选项中声明初始值。
案例
<!--多行文本-->
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
<!--复选框-->
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
...
12、组件
组件是可复用的 Vue 实例,且带有一个名字。我们可以在一个通过 new Vue
创建的 Vue 根实例中,把这个组件作为自定义元素来使用。
基础案例
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
//data 必须是一个函数
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
组件复用
<div id="components-demo">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
prop
Prop 是你可以在组件上注册的一些自定义 属性。当一个值传递给一个 prop 属性的时候,它就变成了那个组件实例的一个 属性
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>
单个根元素
每个组件必须只有一个根元素
v-指令的使用
<div id="blog-posts-events-demo">
<div :style="{ fontSize: postFontSize + 'em' }">
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
</div>
</div>
…
/data 必须是一个函数
data: function () {
return {
count: 0
}
},
template: ‘You clicked me {{ count }} times.’
})
==组件复用==
```html
<div id="components-demo">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
prop
Prop 是你可以在组件上注册的一些自定义 属性。当一个值传递给一个 prop 属性的时候,它就变成了那个组件实例的一个 属性
Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})
<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>