梦入琼楼寒有月,行过石树冻无烟

📖 earlier posts 📖

Vue 事件处理

在vue当中,还提供了一个v-on指令来监听DOM事件,并使用一些鼠标、键盘方法来运行一些js code,其中我们在上面几章已经讲述了v-on指令的缩写为@,本文我们将不会重复上述关于v-on指令的信息。

鼠标左击处理 (@click \ v-on:click)

1
2
3
4
5
6
7
8
9
10
11
12
<div id="app">
<button @click="click += 1">增加</button>
<p>当前增加次数为 {{click}} 次</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
click: 0
}
})
</script>

方法调用


在上述的code中,如果用于复杂逻辑处理那么会直接写上 js code 是不可行的,所以vue自然而然的为我们提供了调用方法的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="app">
<button v-on:click="add">Add</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
counter: 0
},
methods: {
add: function(event) {
alert("当前数据默认被点击次数" + this.counter)
if (event) {
alert("被触发元素为:" + event.target.tagName)
}
}
}
})
</script>

内链调用处理


在上述我们演示到了方法调用以及鼠标动作处理等操作,其中鼠标左击处理也是通过内链直接调用的,所谓内链就是与html 标签元素写在一起即大多数都被称之为内链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app">
<button @click="echo('Hello,vue!')">Vue!</button>
<button @click="echo('Hello,hello!')">Hello!</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
echo: function(message) {
alert(message)
}
}
})
</script>

修饰符

在之前我们讲到了vue的基本事件修饰符,本文我们紧接着上述内容进行详细讲解,首先:

v-on

鼠标修饰符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
```vue
<div id="app">
</div>
<form v-on:submit.prevent="onSubmit">
<a v-bind:href="url">Go blog</a>
</form>
<script>
var app = new Vue({
el: '#app',
data: {
url: 'http://sif_one.gitee.io/'
}
})
</script>

那么其最后在 v-on指令的笼罩下范围内的<a>标签将会失去原本的作用:

ID DA FA
.stop 调用 event.stopPropagation() 停止传播
.prevent 调用 event.preventDefault() 防止默认
.capture 添加事件侦听器时使用capture(捕获) 模式
.self 只当事件从侦听器绑定元素本身触发时才进行回调
```.{keyCode keyAlias} ``` 只当事件从特定键触发时才进行回调
.native 监听组件根本元素的原生事件
.once 只触发一次回调
.left 只当点击鼠标左键时触发
.right 只当鼠标点击右键时触发
.middle 当鼠标中键时触发
.passive 以 { passive: true } 模式添加侦听器

在上述的修饰符中,在事件处理中经常会调用到event.stopPropagation以及event.stopPropagation等方法,但由于其主要处理纯粹的数据逻辑,并不处理BOM事件的写接

于是,vue为了解决这个问题,官方为其提供了事件的修饰符:

  1. stop
  2. prevent
  3. capture
  4. salf
  5. once
  6. passive

当然vue官方文档还提供了几个修饰符的组合例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 阻止单击事件继续传播 -->
<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>

在以上的修饰符进行组合的时候,请需要注意顺序,顺序不同可能最后表达的效果可能不一。。

不仅仅这样

众所周知,jq很多方法都需要使用鼠标事件,如鼠标单击事件,而vue 在2.2.0版本中,也增加了一个鼠标按钮修饰符:

ID DA
.left
.right
.middle

键盘修饰符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

```vue
<div id="app">
<input v-on:keyup.tab="echo">
</div>
<script>
var app = new Vue({
el: '#app',
data: {
echo: function(message) {
alert("监听到了 tab 的键盘事件")
}
}
})
</script>


在上述的code案例中,我们主要使用tab案件码来配合键盘修饰符来监听tab的键盘事件,vue一共所支持的按键修饰符共有9个,分别为:

ID DA
.enter
.tab
.delete
.esc
.space
.up
.down
.left
.right

系统修饰符

当然,vue的v-on指令还不仅仅以上这些,自然而然的还支持了系统修饰符,我们可以通过按下响应的按键触发监听器:

ID DA
.ctrl
.alt
.shift
.meta win 键 或 ⌘ 键

同样的,系统修饰符也可以进行组合,如官方文档中所提供的例子:

1
2
3
4
5
<!-- Alt + C -->
<input v-on:keyup.alt.67="clear">

<!-- Ctrl + Click -->
<div v-on:click.ctrl="doSomething">Do something</div>

需要注意的是,修饰符键于常规的不同,当keyup事件一起使用的时候,修饰符键必须处于按下的状态,只有当按住tab的情况下释放其他案件,才能被触发,所以如果需要实现那种行为,可以改为键代码为keyup.17即可。

.exact
2.5.0中所新增的修饰符,可以**精确的控制系统修饰符组合并触发事件**,这里我们提供了vue的官方文档中所写的例子:
1
2
3
4
5
6
7
8
9
```vue
<!-- 即使 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>

从例子中可以看到使用.exact修饰符进行系统修饰符的多种组合变得更加方便(且不用写键代码如keyup.17

Vue for


除了vue所提供的v-if指令之外,还提供了另一用于多次渲染元素的模块指令v-for,首先需要提供遍历的元素别名格式为:

1
表达式 is 别名

当然我们也可以使用v-for指令并基于数组来渲染列表,通常items是源数据数组,而item则是被迭代的数组元素别名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="app">
<p v-for="item in items" :key="item.message">
{{ item.message }}
</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
items: [
{message: 'Vue'},
{message: 'Ajax'},
{message: 'Ejs'},
]
}
})
</script>

父作用域属性(第二参数)


v-for块中还支持访问所有父作用域的属性,v-for并支持第二参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div id="app">
<p v-for="(item, index) in items">
{{title}} - {{index}} - {{ item.message }}
</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
title: 'Hello',
items: [
{message: 'Vue'},
{message: 'Ajax'},
{message: 'Ejs'},
]
}
})
</script>

其中index属性对应的则是输出次数,为v-for所支持的第二参数,其格式为:

1
(表达式 , 表达式二) in 别名 

遍历对象


除了遍历元素之外,for还可以遍历对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
<p v-for="item in items">
{{item}}
</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
items: {
name: 'kun',
age: '10'
}
}
})
</script>

键名:元素


我们可以通过使用vue所提供的另一种方式即键名:元素来循环遍历对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
<p v-for="(value ,name) in items">
{{name}}:{{value}}
</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
items: {
name: 'kun',
age: '10'
}
}
})
</script>

维护状态

v-for渲染元素列表的时候,他会默认使用就地更新的策略,如果数据被改变,vue将不会移动dom元素来匹配数据项的顺序。为了确保他们的每个索引位置正确的渲染

这个时候我们需要为每个节点写入一个唯一的key属性即:

1
2
3
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>

在官方稳定那个中建议尽可能使用 v-for 时所提供的 key属性,除非遍历输出的DOM内容非常简单,或是希望性能上的提升

数组更新检测

变更方法

ID DA FA
push() 增加一个方法
pop() 从下往上突然的删除一个方法
shift() 从上往下删除一个方法
unshift() 从上方新加入一个方法
splice() splice()方法可用于添加、删除、替换数组内的值
sort() 用于排序方法
reverse() 主要用于排序倒序

sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="app">
<p v-for="item in sortItems">
{{ item }}
</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
items: [1,20,2,3,4,100],
},
computed: {
sortItems:function() {
return this.items.sort(sortNumber)
}
},
});
function sortNumber(a,b) {
return a-b
}
</script>

reverse()

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app">
<p v-for="item in items.slice().reverse()">
{{ item }}
</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
items: [1,2,3,4,5,6],
}
})
</script>

Vue 条件

v-if …… v-if-else …… v-else

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
<h1 v-if="message === 'Vue'">Vue</h1>
<h1 v-else-if="message === 'Laravel'">Laravel</h1>
<h1 v-else>
不是 Vue 也不是 Laravel
</h1>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
faq: ' ',
message: 'Vue'
}
})
</script>

当地一个条件满足Vue的时候,则自然而然的显示Vue,但如果第一条件不满足但满足了第二条件Laravel,则自然而然的显示Laravel,如果都不满足则输出v-else指令内的信息。

v-if


vue中我们可以通过使用v-if有条件的渲染一块内容,就比如下述code中的message值如果是true则会显示:

1
2
3
4
5
6
7
8
9
10
11
12
<div id="app">
<h1 v-if="message">Vue is awesome!</h1>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
faq: ' ',
message: false
}
})
</script>

v-else

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app">
<h1 v-if="message">Vue is awesome!</h1>
<h1 v-else="message">Hello,world</h1>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
faq: ' ',
message: false
}
})
</script>

如果将message的值为false,那么则显示v-else内的数据,当v-if符合条件则显示其v-if块的信息。

key

复用 key

通过使用key我们可以管理可复用的元素,且vue也会尽可能的提高渲染的效率,使用可服用的元素的好处就是元素不会从头开始进行渲染,这也使得vue变得稍微快一点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div id="app">
<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>
<button @click="toggleLoginType">Toggle login type</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
loginType: 'username'
},
methods: {
toggleLoginType: function () {
return this.loginType = this.loginType === 'username' ? 'email' : 'username'
}
}
})
</script>


在上述code中,我们主要切换了loginType的值,也就是当不满足username条件的时候切换为else块的placeholder,而使得切换效果的功能主要通过v-on进行实现。

唯一 key


复用key的缺点是表单内的信息也会被同步,而如果设置一个唯一的key,则每个数据都是独立的,服用的只是房子本身而并非里面的装饰物:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div id="app">
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email">
</template>
<button @click="leghtLoginType">Toggle login type</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
loginType: 'username'
},
methods: {
leghtLoginType: function () {
return this.loginType = this.loginType === 'username' ? 'email' : 'username'
}
}
})
</script>

v-show


在前端的开发当中我们经常会使用一个非常棒的方法即display,通常当display的值如果为none则不会进行显示。在vue中,v-show主要用于切换display的CSS 属性:

1
2
3
4
5
6
7
8
9
10
11
<div id="app">
<h1 v-show="show">Hello,Vue</h1>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
show: true
}
})
</script>

当在控制端中执行app.show=false的时候,则此时<h1>标签的css属性将会更改为display: none,则不可见,v-ifv-show的区别可以是:

ID DA
v-if 通过vue进行条件渲染,确保在切换的过程中被销毁和重建
v-show 不管条件如何,元素依然会被显然,只是根据 CSS display 属性进行切换
v-if拥有更高的切换开销,v-show则有更高的初始渲染的开销

Vue 计算属性与侦听

计算属性

尽管vue内的表达式非常便利,但设计他们的初衷依然是用于进行简单的运算,如下方的code主要用于翻转字符串:

1
2
3
4
5
6
7
8
9
10
11
<div id="app">
{{message.split('').reverse().join('')}}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'hello,world'
}
})
</script>

但是如果我们想要在模板中多处翻转字符串的时候就会变得非常繁琐,所以对于复杂的处理我们一般使用computed属性,即```所有getter和setter上的this上下文都会被绑定在Vue的实例中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
{{ reversedMessage }}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'hello,world'
},
computed: {
reversedMessage: function() {
return this.message.split('').reverse('').join('')
}
}
})
</script>


在此时,我们首先声明了一个计算属性为reversedMessage,并提供了函数将作特征为 app.reversedMessagegetter函数,同样的我们也可以在控制台中通过使用app.message="vue"来进行修改。

通过计算属性,vue知道app.reversedMessage依赖或引用于app.message所以当app.message发生改变的时候,依赖他的数据自然会被更新。

计算属性和方法

在官方文档中该标题为 计算属性 vs 方法很显然虽然两者最后都会达到同样的效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id="app">
{{ reversedMessage() }}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'hello,world'
},
methods: {
reversedMessage: function() {
return this.message.split('').reverse().join('')
}
}
})
</script>

但是不同的是计算属性是基于他的响应式依赖进行缓存的,当相关响应式以来发生改变的时候才会重新渲染,所以这就意味着只要````app.message没事不进行该ian,多次访问reversedMessage```并不会立即返回计算之前的效果或再次执行

相比之下与每次访问都要重新进行寻安然,调用方法然后在再次执行函数的操作很明显前者较为优秀。

计算属性和侦听属性

vue为我们提供了一种更加通用的方式来观察响应vue实例上的数据变动即watch的侦听属性,当有一些数据需要随着其他数据进行变动的时候,可以使用watch属性

watch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
var app = new Vue({
el: '#app',
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
}
}
})
</script>

computed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
var app = new Vue({
el: '#app',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
computed: {
fullName: function () {
return this.firstName + '' + this.lastName
}
}
})
</script>
ID DA
watch
computed

通过上述的演示我们就可以非常轻松的了解到watch的作用,当很多数据需要随着其他数据改变而改变的时候,这个时候使用watch就非常的适当,而computed对于单个的数据较为有优势。

getter 与 setter

1
2
getter 与 setter
getter 主要用于检索变量,而setter则用于更新变量的值

computed默认用于检索变量,如果想实现于watch差不多的作用那么我们可以增加一下setter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<div id="app">
{{ fullName }}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
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]
}
}
}
})
</script>

侦听器


vue为开发者所提供了一种更加丝滑的API为watch,vue在实例化的同时调用watch,来遍历 watch对象内的所有属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<div id="app">
<input v-model="faq">
<p>{{answer}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
faq: ' ',
answer: '请输入信息'
},
watch: {
faq: function(newQuestion, oldQuestion) {
this.answer = '正在输入……'
this.debouncedGetAnswer()
}
},
created: function() {
this.debouncedGetAnswer = _.debounce(this.getAnswer,500)
},
methods: {
getAnswer: function() {
if(this.faq.indexOf('?') === -1) {
this.answer = '输入的时候请加上一个问号'
return
}
this.answer = '正在检索'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function(response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function(error) {
vm.answer = 'API内并没有此数据' + error
})
}
}
})
</script>

Vue 模板语法

Vue.js主要使用了基于HTML的模板语法,允许开发者声明式的将DOM绑定至底层的Vue实例数据,由于Vue.js基于HTML模板语法,所以所编写的自然而然能被浏览器所解析(除了远古浏览器)。

插值

插值主要包含了文本、原始HTML、属性、原始表达式等四类,其中我们会在本章一一进行介绍:

文本

Mustache

在Vue.js中,常见的数据绑定形式就使用Mustache语法来进行插值,即<p>{{message}}</p>,这里的Mustache是一款经典的前端模板引擎,而Mustache的价值在其稳定以及经典,其中在Vui内的{{……}}写法就类似与Mustache模板引擎的语法:

1
<p>{{ message }}</p>

v-once

效果
Vue.js为我们提供了一个类似与Object.freeze()阻止修改的方法,而vue又为我们提供了另一种方法即v-once指令,通过v-once指令我们可以进行一次性插值,当数据改变的时候,内容将不会被更新.

1
2
3
4
5
6
7
8
9
10
11
<div id="app">
<span v-once>{{ message }}</span>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
message: 'Hello,world'
}
})
</script>

原始 HTML

通常在为我们提供指令的时候一般都会提供一个输出原始HTML的指令。Vue并不例外,Vue所提供的指令是v-html,即:

1
<div v-html="html"></div>

建议

v-html指令预期是字符串类型,内容按照HTML进行插入,不会被当作vue模板进行编译。使用v-html指令可能会出现一些安全问题,所以我们尽量在一些不容易发生问题的地方使用。

v-bind

v-bind:id


在默认的情况下Mustache语法并不能使用在HTML 属性中(在vue编译的范围内),当遇到这种情况的时候我们可以使用v-bind指令:

1
2
3
4
5
6
7
8
9
<div v-bind:id="app">{{Hello}}</div>
<script>
var vm = new Vue({
el: "#app",
data: {
message: 'Hello,world'
}
})
</script>

如果你还不能理解上面的Code以及v-bind指令,我们可以通过下方code来进行理解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div v-bind:id="app">{{Hello}}</div>

<div id="app">
<p>{{hello}}</p>
</div>

<script>
var vm = new Vue({
el: "#app",
data: {
message: 'Hello,world'
}
})
</script>

在上述的code中,使用v-bind指令的html属性将会在vue编译的范围内进行输出,而未使用b-bind指令的html属性将不会进行输出。

v-bind:src


通过使用v-bind:src指令,我们可以绑定一个src属性的比如img元素:

1
2
3
4
5
6
7
8
9
10
11
<div id="app">
<img v-bind:src="img" alt="">
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
img: 'https://img-home.csdnimg.cn/images/20201124032511.png'
}
})
</script>

当然v-bind指令还可以支持缩写为:,及上述img元素重构为:

1
<img :src="img" alt="">

v-pind:class


除了id~src之外,还支持class等方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<style>
.red {
color: red;
}
</style>
<body>
<div id="app">
<p v-bind:class="colorRed">Hello,world</p>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
colorRed: 'red'
}
})
</script>
1
2
3
4
```vue
<div id="app">
<p v-bind:class="[one, two]">Hello,world</p>
</div>

Vue 通过class red添加到vue的渲染队列中,最后使用v-pind:class来引入colorRed

v-pind:style

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<style>
.red {
color: red;
}
</style>
<body>
<div id="app">
<p v-bind:style="colorRed">Hello,world</p>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
colorRed: {
color: 'red',
fontSize: "20px"
}
}
})
</script>
1
2
3
4
```vue
<div id="app">
<p v-bind:style="[one, two]">Hello,world</p>
</div>

v-pind:href

除了以上的几种v-pind参数之外,自然还支持了href参数

1
2
3
4
5
6
7
8
9
10
11
<div id="app">
<a v-bind:href="url">Go blog</a>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
url: 'http://sif_one.gitee.io/'
}
})
</script>

JavaScript 表达式


vue对javascript表达式有良好的支持,且并不限于表达式,甚至包括语句:

1
2
3
4
5
6
7
8
9
10
11
<div id="app">
{{message + ',vue!'}}
</div>
<script>
var app =new Vue({
el: '#app',
data: {
message: 'hello'
}
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<div id="app">
{{ ok ? 'YES!' : 'NO!' }}<br>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
ok: false,
}
})
</script>
```
## 指令
![](https://49812933408852955071488026628034-1301075051.cos.ap-nanjing.myqcloud.com/1615219482_20210308231156016_218446905.gif)
指令即(Directives)则在vue中则是代表有```v-```前缀的特殊属性,当表达式改变的时候也会将行为应用到DOM内:
```vue
<div id="app">
<p v-if="seen">Hello,world!</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
seen: true,
}
})
</script>

由于将属性加入到了DOM对象内,所以我们可以通过控制台来进行操作对象,就如本文中我们将此来实现显示以及隐藏等。

参数


当介绍完指令之后,自然而然的就是轮到了参数,就以上述的code为例子,v-if为属性,而seen为参数,如果要写我们可以这样:

1
2
3
4
5
6
7
8
9
10
11
<div id="app">
<a v-bind:href="url">Go blog</a>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
url: 'http://sif_one.gitee.io/'
}
})
</script>

修饰符

v-on

1
2
3
4
5
6
7
8
9
10
11
12
13
14
```vue
<div id="app">
</div>
<form v-on:submit.prevent="onSubmit">
<a v-bind:href="url">Go blog</a>
</form>
<script>
var app = new Vue({
el: '#app',
data: {
url: 'http://sif_one.gitee.io/'
}
})
</script>

那么其最后在 v-on指令的笼罩下范围内的<a>标签将会失去原本的作用:

ID DA FA
.stop 调用 event.stopPropagation() 停止传播
.prevent 调用 event.preventDefault() 防止默认
.capture 添加事件侦听器时使用capture(捕获) 模式
.self 只当事件从侦听器绑定元素本身触发时才进行回调
```.{keyCode keyAlias} ``` 只当事件从特定键触发时才进行回调
.native 监听组件根本元素的原生事件
.once 只触发一次回调
.left 只当点击鼠标左键时触发
.right 只当鼠标点击右键时触发
.middle 当鼠标中键时触发
.passive 以 { passive: true } 模式添加侦听器

缩写

虽然已经在上述说明中标注了其指令的缩写,但为了视觉效果和让读者感觉非常重要,还是要单独列一个标题来着重标注

Vue.js最为不同且便捷的方式就是,基本上每个指令都会有一个缩写,其中v-前缀作为一种视觉提示,可用来辨别vue特定的属性,就如本文我们所出现的 v-bindv-on缩写分别为:以及@

Vue 实例与 MVVM

MVVM

MVVM是Model-View-ViewModel的缩写,即模型-视图-视图模型,MVVM最早是由微软所提出,主要借鉴了MVC的思想,前端页面中,将模型用Javascript对象表示,View负责显示,而将模型与视图关联起来的叫 ViewModel,ViewModel负责将模型数据同步到视图显示。

如果说到Vue前面为什么要举那么多修改DOM的例子,那无非就是之为读者学习 Vue 实例所铺路,虽然Vue并没有完全的遵守 MVVM模型但是Vue受到了启发。

如果你说jquery与vue来修改DOM节点的区别那么我们可以使用以下例子来进行分别,你会发现vue的确是受到了 MVVM 的启发:

jquery

1
2
var name = 'jquery';
$('#name').text(name);

MVVM

1
2
3
4
5
6
7
8
9
10
11
12
var person = {
name: 'Bart',
};
```
当改变 JavaScript对象的时候,也将会导致DOM结构或数据作出相应的变化,MVVM的出现让我们的从如何操作DOM变成了**如何改变JavaScript**对象数据或状态,这也是MVVM的设计思想之一。

## 创建一个 Vue 实例
Vue的应用创建可以通过 Vueh函数来创建一个新的实例开始,如:
```vue
var vm = new Vue({
// code
})

虽然 Vue并没有完全遵循 MVVM模型,但是其设计也收到了启发,所以在其官方文档中依然会使用vm即(ViewModel)缩写来作为 Vue 的实例。

数据与方法

在Vue实例被创建的时候,他会将 data对象中的所有属性加入到 vue内,当这些属性的值发生改变的时候,试图将会产生一个响应,来匹配更新为新的值:

1
2
3
4
5
6
var vm = new Vue({
el: "#app",
data: {
message: 'Hello,world'
}
})

当这些数据被改变的时候,视图会进行重新渲染

只有当实例被创建的时候就已经存在data中的属性才是响应式的,如果你在控制台内想新添加一个属性,且一开始他为空且不存在,那么将不会触发任何的视图更新,此时需要设置初始值,详情可以查看官方文档内的 : https://vuejs.bootcss.com/guide/instance.html 章节。

当然有了初始值,以及修改的,自然会出现一个组织修改现有属性的方法即Object.freeze(),即:
效果

1
2
3
4
5
6
7
var vm = new Vue({
el: "#app",
data: {
message: 'Hello,world'
}
})
Object.freeze(vm)

Vue 自定义指令


在接触 Vue 自定义指令的之前,我们需要了解到 钩子函数,在 Windows 中,钩子函数实在 Windows 消息处理机制中的一部分,可以通过设置钩子来实现自己想要的需要效果。在 Vue 中每个被创建的实例都需要经过一系列初始化的过程,如果需要设置数据监听、编译或挂载DOM时,会调用一个生命周期的钩子,而此时我们可以在此加入一些code来实现自己想要的效果。

钩子函数

钩子函数即在Vue实例中插入一段code来满足自己下需求,截至vue 2.x 版本内,共支持的钩子函数共有:

ID DA
bind 只调用一次,指令第一次绑定到元素的时候调用,一般进行一次性的初始化设置
inserted 被绑定元素插入父节点时调用
update 被绑定元素的模板被更新时进行调用,无论绑定值是否变化。通过比较更新前和更新后的值,可以忽略不必要的模板进行更新
componentUpdate 被绑定的元素所在模板完成一次新的周期时被调用
unbind 指令与元素解绑时进行调用一次

钩子参数

ID DA
el 指令绑定的元素
binding 一个对象且包含以下属性
name 指令名(不需要包括 v- 前缀)
value 指令的绑定值
oldValue
expression 字符串形式的表达式指令
arg 传给指令的参数,如 v-directive:foo其中参数为 foo
modifiers
vnode Vue 编译生成的虚拟节点
oldVnode 上一个虚拟节点,仅在 update 、 componentUpdated 钩子中使用```

自定义指令

全局指令

我们以一个非常经典的案例作为一个例子,当页面加载的时候,该选素将会获得焦点:

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="app">
<input v-focus>
</div>
<script>
Vue.directive('focus', {
inserted: function(el) {
el.focus()
}
})
new Vue({
el: '#app'
})
</script>

通过 directive我们注册了一个名为focus的全局组件,其主要作用就是:“当该页面加载的时候”,他会自动获取焦点仅此而已,并且我们还使用了inserted钩子函数,以用于绑定父节点中欧调用focus

局部指令

通常而言,全局自定义指令与局部自定义指令之间的区别可以从code看出,全局注册指令是单独来写的即:

1
2
3
4
5
Vue.directive('focus', {
inserted: function(el) {
el.focus()
}
})

而局部自定义指令是在初始化vue时写的,即之可以在本身的Vue实例中进行使用,除此之外他们之间的区别还可以是一个是通过directive来定义,另一个则是通过使用directives来实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="app">
<input v-focus>
</div>
<script>
new Vue({
el: '#app',
directives: {
focus: {
inserted: function(el) {
el.focus()
}
}
}
})
</script>

Vue 动态组件

初始化


在通常情况下,不同组件之间的动态切换可以让页面变得更加的拥有趣味,且可以减少一些不必要的从页面占用。动态组建可以用于构建一些非动态的填写,而如果需要满足一些OAuth等切换或登录的场景,则需要使用 Vue 动态组件中的异步组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<div id="example">
<button @click="methodsAll">Go</button>
<component v-bind:is="componentView"></component>
</div>
<script>
var one = {
template: `
<div>one Template</div>
`
};
var two = {
template: `
<div>two Template</div>
`
};
var three = {
template: `
<div>three Template</div>
`
};
new Vue({
el: '#example',
components: {
one,
two,
three,
},
data:{
index:0,
list:['one','two','three'],
},
computed:{
componentView(){
return this.list[this.index];
}
},
methods:{
methodsAll(){
this.index = (++this.index)%3;
}
}
})
</script>

keep-alive

Vue创建一个新的 ```componentView``` 实例,也就是说只要通过使用```keep-alive```方法进行包裹,即可让他们在```第一次```创建时会被进行**缓存**,即保存刚刚切换后的数据,为了更加的体现```keep-alive```效果,我们可以使用表单来进行验证:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

| ID | DA |
| --- | --- |
| 使用 keep-alive | ![](https://49812933408852955071488026628034-1301075051.cos.ap-nanjing.myqcloud.com/1615860798_20210316101115343_930785737.gif) |
| 不使用 keep-alive | ![](https://49812933408852955071488026628034-1301075051.cos.ap-nanjing.myqcloud.com/1615860799_20210316101142717_305448193.gif) |
```vue
<div id="example">
<button @click="methodsAll">Go</button>
<keep-alive>
<component v-bind:is="componentView"></component>
</keep-alive>
</div>
<script>
var one = {
template: `
<input type="text">
`
};
var two = {
template: `
<div>two Template</div>
`
};
var three = {
template: `
<div>three Template</div>
`
};
new Vue({
el: '#example',
components: {
one,
two,
three,
},
data:{
index:0,
list:['one','two','three'],
},
computed:{
componentView(){
return this.list[this.index];
}
},
methods:{
methodsAll(){
this.index = (++this.index)%3;
}
}
})
</script>

Vue 插槽


插槽在Vue组件中,是一个极为不可缺少的一个部分,对于插槽,我们可以理解为我们首先定义了一个 Error,之后通过使用<slot>元素让其输出关于Error后相关的内容,这在 Vue中通常被称之为后备内容

默认插槽

1
2
3
4
5
6
7
8
9
10
11
12
13
    <div id="app">
<solt-name></solt-name>
</div>
<script>
Vue.component('soltName', {
template: `
<div>Hello</div>
`
})
var vm = new Vue({
el: '#app',
})
</script>

后备内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    <div id="app">
<solt-name>world!</solt-name>
</div>
<script>
Vue.component('soltName', {
template: `
<div>Hello,
<slot></slot>
</div>
`
})
var vm = new Vue({
el: '#app',
})
</script>

具名插槽


有时候我们如果需要多个插槽,那么通俗的来讲就是为分配一个名字,在一般的情况下没有名字的插槽将会被认定为是一个默认插槽,在上图中,我们主要定义了导航、正文、结尾等三个插槽,其中默认插槽被应用在导航中,而正文、结尾主要被具名插槽中的two以及three进行填写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<style>
.orset {
margin-top: 10%;
}
</style>
<div id="app">
<solt-name>
<div class="orset" slot="two">正文</div>
<div class="orset" slot="three">结尾</div>
</solt-name>
</div>
<script>
Vue.component('soltName', {
template: `
<div>
<solt>默认插槽</solt>
<slot name="two"></slot>
<slot name="three"></slot>
</div>
`
})
var vm = new Vue({
el: '#app',
})
</script>

作用域插槽


作用域插槽作为 vue 插槽中最为详细的一部分不仅仅是适用范围广,通常还可以搭配着 vue 指令来进行输出,本次案例我们主要会通过使用for来循环以及使用if来分别针对且有条件的对数据进行输出与使用:

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<div id="app">
<slot-name :lists="Teamname">
<template slot-scope="slotvm">
{{slotvm}}
</template>
</slot-name>
</div>
<script>
Vue.component('slotName', {
props: ['lists'],
template: `
<div>
<p v-for="list in lists">
<slot v-bind="list"></slot>
</p>
</div>
`
})
var vm = new Vue({
el: '#app',
data: {
Teamname: [
{ id:1, name: 'Jiangxue' },
{ id:2, name: 'Sif one' },
{ id:3, name: 'ZhongShan' }
]
}
})
</script>

条件输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<div id="app">
<slot-name :lists="Teamname">
<template v-if="slotvm.id==1" slot-scope="slotvm">
{{slotvm.name}}
</template>
</slot-name>
</div>
<script>
Vue.component('slotName', {
props: ['lists'],
template: `
<div>
<p v-for="list in lists">
<slot v-bind="list"></slot>
</p>
</div>
`
})
var vm = new Vue({
el: '#app',
data: {
Teamname: [
{ id:1, name: 'Jiangxue' },
{ id:2, name: 'Sif one' },
{ id:3, name: 'ZhongShan' }
]
}
})
</script>

在上述code中,我们首先将数据使用v-for来进行循环输出,之后在通过使用v-if以及使用v-bind来进行绑定属性,最终通过满足条件即 Teamname中,id 为1的键值名称得到且输出。

va: http://jsrun.net/v2NKp/edit

Vue 自定义事件

事件在vue中主要被定义为当你点击他的时候,他会作出什么反映,这就比如我们前几章所介绍的当按下鼠标时,则值每次分别增加1,则这种被称之为“事件”。

事件命名

Vue的事件命名不同于 prop,即事件名不存在任何的自动化大小写转换,即触发、监听的事件必须完全匹配这个事件所用的名称,如:

1
this.$emit('eventName')

事件定义


在Vue 中我们可以通过使用v-on指令或者@来简写作为 DOM 元素的事件绑定,而除此之外我们还可以使用 Vue 事件接口(Eventd interface)中的

  1. $on (eventName)
  2. $emit(eventName)

通过上述 Vue 接口事件,可分别使用$on来进行监听事件以及将$emit用于触发事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<div id="app">
<div id="event-example">
<button-event v-on:event="eventGo"></button-event>
<button-event v-on:event="eventGo"></button-event>
</div>
</div>
<script>
Vue.component('button-event', {
template: '<button v-on:click="increaseUp">{{ echo }}</button>',
data: function() {
return {
echo: 0
}
},
methods: {
increaseUp: function() {
this.echo +=1
this.$emit('event')
}
},
})
new Vue({
el: '#event-example',
data: {
total: 0
},
methods: {
eventGo: function() {
this.total += 1
}
}
})
</script>

v-model 自定义组件

表单


Vue 中v-model指令可以用于在表单或组件上自动创建一个双向的绑定,就为明显的例子无非就是获取表单输入,通过表单输入以及获取表单输入即可是一个双向绑定,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div id="app">
<model-input v-model="number"></model-input>
<p>{{number}}</p>
</div>
<script>
Vue.component('model-input', {
template: `
<input ref="input" :value="value" @input="$emit('input',$event.target.value)">
`,
props: ['value'],
})
new Vue({
el: '#app',
data: {
number: null,
}
})
</script>

多选


在上述的流程图中,我们合租要通过使用v-on以及v-show来分别判断鼠标事件以及真假值的判断,当check被点击的时候,则默认将v-show改变为 true状态使得其变得可见,默认为false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<div id="app">
<show-checkbox v-model="check"></show-checkbox>
<div v-show="check">
以同意相关注册协议
</div>
</div>
<script>
Vue.component('show-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
<input type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)"
>
`
})
new Vue({
el: '#app',
data: {
check: false
}
})
</script>
📖 more posts 📖