Vue学习笔记(2)

vue的指令(下)

内置指令( 下)

先把内置指令搞完(

Clause

v-bind

如果说插值是对innerHTML的操作,那么v-bind就是对属性的操作。

考虑下面一个例子:我们要根据数据动态修改某个图片。我们可以用这样的操作:

1
2
3
4
5
6
7
8
9
10
11
<div id="hello">
<img v-bind:src="'src/'+picName">
</div>
<script>
const vm = new Vue({
el : '#hello',
data: {
picName: '1.png'
}
});
</script>

v-bind可以简写成:。除此之外,我们也允许动态属性名的存在:

1
2
3
4
5
6
7
8
9
10
11
12
<div id="hello">
<img :[attrname]="'src/'+picName">
</div>
<script>
const vm = new Vue({
el : '#hello',
data: {
attrname: 'src',
picName: '1.png'
}
});
</script>

这里要注意一点,属性名在浏览器中是不区分大小写而默认作为小写存在的。所以此处如果Vue对象中使用大写,就会导致找不到对应的属性名。

v-on

大家都喜欢的监听器。最简单的事件就是click了,举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="hello">
<p key="qwq">{{idx}}</p>
<button @click="addIdx">Click</button>
</div>
<script>
const vm = new Vue({
el : '#hello',
data: {
idx: 6
},
methods: {
addIdx: function() {
++this.idx;
}
}
});
</script>

@v-on的简写。

一定不要使用箭头函数定义methods方法,否则绑定会出现问题。

在js中有事件捕获和冒泡的概念,并引入了preventDefault()。Vue中也是如此,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="hello">
<a href="lirewriter.cn" @click="qaq($event)">qwq</a>
</div>
<script>
const vm = new Vue({
el : '#hello',
methods: {
qaq: function(e) {
alert("haha");
e.preventDefault();
}
}
});
</script>

这样的处理是较为繁琐的。Vue提供了许多事件修饰符,可以让我们关注于数据逻辑。

  • .stop 调用event.stopPropagation()
  • .prevent 调用event.preventDefault()
  • .capture 事件监听器为捕获
  • .self 本身触发的时候才回调
  • .once 只触发一次回调
  • .left/.right/.middle 按左/右/中的时候触发

这样,上面的代码可以简化为

1
<a href="lirewriter.cn" @click.prevent="qaq">qwq</a>

此外,Vue也有按键修饰符keyup,并给了常用按键码的一些别名:

  • .enter
  • .tab
  • .delete(包括删除、退格)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

例如下面的代码,可以用来响应回车提交表单:

1
<input @keyup.enter = "submit">

同时,Vue也提供了一下按键的监听器支持:

  • .ctrl
  • .alt
  • .shift
  • .meta(window键或command键)

可以实现当且仅当按下键的同时操作才生效的功能:

1
2
<input @keyup.alt.delete = "clear">
<div @click.ctrl = "qwq">qwq</div>

v-text和v-html

可以把插值改为属性的奇妙指令。

1
<span v-text="qwq"></span>

这一指令和

1
<span>{{qwq}}</span>

是一致的。

类似的,v-html可以改变html。

v-once

这个可以保证植渲染一次。比如我们翻出昨天的某个例子,但是稍微变一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="hello">
<ul>
<li v-for="ele in items" v-once>{{ele.title}}</li>
</ul>
</div>
<script>
const vm = new Vue({
el : '#hello',
data: {
items: [
{title: 'qwq'},
{title: 'qaq'},
{title: 'ovo'}
]
}
});
</script>

这样,假如我们在控制台调用

1
vm.$data.items.push({title: "uau"});

页面不会变化,因为渲染只有一次。

v-pre

这个指令可以禁止渲染。比如你要插值的地方整个这个,就会显示两个大括号。

v-cloak

这个指令可以用来解决闪烁问题。如果页面很大,可能在某一段时间插值会按原来的样子显示出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    <style>
[v-cloak] {
display: none;
}
</style>
...
<body>
<!--View-->
<div id="hello">
<h1 v-cloak>{{message}}</h1>
</div>
<script>
const vm = new Vue({
el : '#hello',
data: {
message: 'qwq'
}
});
</script>
</body>

自定义指令注册

Vue的指令可以写在direcrives里。这里又可以分成全局和局部的区别。

1
Vue.directive('qwq', {})

可以注册全局指令。而

1
2
3
4
5
6
new Vue({
el: '#app',
directives: {
qwq: {..}
}
})

可以注册局部指令。

在指令中,最关键的一点就是钩子函数。钩子函数可以看作一种事件监听器,在某些事件触发的时候调用该函数:

  • bind,在指令第一次绑定时候调用。可以看作初始化的时候调用。
  • inserted,在元素插入父节点时候调用。
  • update,Vnode更新时候调用。
  • componentUpdated,VNode和子VNode全部调用后调用。
  • unbind,解绑时调用。

我们以bind为例,说明用法:

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.staticfile.org/vue/2.6.11/vue.js"></script>
</head>
<body>
<div id="app" v-demo:foo.a.b="message">

</div>
<script>
Vue.directive('demo', {
bind: function (el, binding, vnode) {
let s = JSON.stringify;
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: '+ s(binding.value) + '<br>'+
'expression: ' + s(binding.arg) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys' + Object.keys(vnode).join(', ')
}
});
new Vue({
el: '#app',
data: {
message: 'qwq'
}
});
</script>
</body>
</html>

我们来解释一下bind这个函数中参数的含义。

el指代的是绑定元素,所以我们可以直接操作el.innerHTML。

binding是绑定对象,包含如下属性:

  • name 指令名
  • value 指令的绑定值,说白了就是对应的表达式。比如v-myname="1+1"结果是2.
  • oldValue 绑定的前一个值,仅在update和componentUpdate可用
  • expression 字符串形式。比如v-myname="1+1"结果是1+1。
  • arg 传入参数
  • modifiers 修饰符,类似于.prevent之类的

v-node是Vue编译生成的虚拟节点。

在实际操作的时候,大部分情况下binding与update可以同时发生。此时可将函数进行简化:

1
2
3
Vue.directive('color-switch', function(el, binding) {
el.style.backgroundColor = binding.value;
});

下拉菜单

大家都喜欢的下拉菜单又来了()

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.staticfile.org/vue/2.6.11/vue.js"></script>
<style>
body {
width: 600px;
}
a {
text-decoration: none;
display: block;
color: #fff;
width: 120px;
height: 40px;
line-height: 40px;
border: 1px solid #fff;
border-width: 1px 1px 0 0;
background: #255f9e;
}
li {
list-style-type: none;
}
#menu > li {
list-style-type: none;
float: left;
text-align: center;
position: relative;
}
#menu li a:hover {
color: #fff;
background: #ffb100;
}
#menu li ul {
position: absolute;
left: -40px;
top: 40px;
margin-top: 1px;
font-size: 12px;
}
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="menu" v-cloak>
<li v-for="menu in menus" @mouseover="menu.show=true" @mouseout="menu.show=false">
<a :href="menu.url"> {{menu.name}} </a>
<ul v-show="menu.show">
<li v-for="subMenu in menu.subMenus">
<a :href="subMenu.url">{{subMenu.name}}</a>
</li>
</ul>
</li>
</div>
<script>
const vm = new Vue({
el: "#menu",
data: {
menus: [
{
name: '旧作', url: '#', show: false, subMenus: [
{name: '东方灵异传', url: '#'},
{name: '东方封魔录', url: '#'}
]
},
{
name: '新作', url: '#', show: false, subMenus: [
{name: '东方神灵庙', url: '#'},
{name: '东方鬼形兽', url: '#'}
]
}
]
}
})
</script>
</body>
</html>

结果归根结底难点还是在css上(

# JS, Vue, 前端

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×