Vue.js入门-2-模板语法

模板语法、计算属性和观察者、Class 与 Style 绑定

模板语法

插值

文本

数据绑定最常见的就是Mustache语法(双大括号)文本插值。可以进行响应式绑定

1
<span>Message: { {  msg  } }</span>

使用v-once指令,可以一次性的插值,当数据改变时不会更新

1
<span v-once>这个将不会改变: { {  msg  } }</span>

原始HTML

使用v-html,被插入的内容都会当做HTML处理。但容易导致XSS攻击

1
2
<p>Using mustaches: { {  rawHtml  } }</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>

特性

Mustache语法不能再属性里使用。在属性中需要使用v-bind

1
<div v-bind:id="dynamicId"></div>

使用JavaScript表达式

对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{ {  number + 1  } }
{ { ok ? 'YES' : 'NO' } }
{ { message.split('').reverse().join('') } }
<div v-bind:id="'list-' + id"></div>
```





每个绑定都只能包含单个表达式,所以**下面的例子都不会生效**。

```js
<!-- 这是语句,不是表达式 -->
{ { var a = 1 } }

<!-- 流控制也不会生效,请使用三元表达式 -->
{ { if (ok) { return message } } }

模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如 Math 和 Date 。你不应该在模板表达式中试图访问用户定义的全局变量。

指令

指令 (Directives) 是带有 v- 前缀的特殊属性。指令属性的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。

参数

一些指令能够接收一个“参数”,在指令名称之后以冒号表示。

1
2
<a v-bind:href="url">...</a>
<a v-on:click="doSomething">...</a>

修饰符

修饰符 (Modifiers) 是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault():

1
<form v-on:submit.prevent="onSubmit">...</form>

缩写

Vue.js 为 v-bind 和 v-on 这两个最常用的指令,提供了特定简写:

1
2
3
4
5
6
7
8
9
10
11
<!-- 完整语法 -->
<a v-bind:href="url">...</a>

<!-- 缩写 -->
<a :href="url">...</a>

<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>

<!-- 缩写 -->
<a @click="doSomething">...</a>

计算属性和观察者

计算属性

模板中绑定表达式只用于简单的操作。如果需要进行逻辑操作,应当使用计算属性 computed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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>

结果:

Original message: “Hello”

Computed reversed message: “olleH”

vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新。

计算属性缓存 vs 方法

1
2
3
4
5
6
7
8
9
<p>Reversed message: "{ {  reversedMessage()  } }"</p>
<script>
// 在组件中
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
</script>

方法计算属性两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。

计算属性只有在它的相关依赖发生改变时才会重新求值。

计算属性 vs 侦听属性

Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。

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

当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch,通常更好的做法是使用计算属性而不是命令式的 watch 回调。

1
2
3
4
5
6
7
8
9
10
11
12
var vm = new Vue({ 
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})

计算属性的 setter

计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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.firstNamevm.lastName 也会相应地被更新。

侦听器

当你想要在数据变化时,执行异步操作或开销较大的操作,这是很有用的。例如Ajax

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
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{ { answer } }</p>
</div>

<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<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 watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.getAnswer()
}
},
methods: {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
getAnswer: _.debounce(
function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
},
// 这是我们为判定用户停止输入等待的毫秒数
500
)
}
})
</script>

在这个示例中,使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

Class 与 Style 绑定

绑定 HTML Class

对象语法

可以传给 v-bind:class一个对象,以动态切换class。下面语法表示如果isActive为真,则就给divclass赋值active

1
<div v-bind:class="{  active: isActive  }"></div>

绑定class与原有class不冲突。可以传多个值来切换多个class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>

和如下 data:

data: {
isActive: true,
hasError: false
}

结果渲染为:

<div class="static active"></div>

如果 hasError 的值为 true,class 列表将变为 "static active text-danger"。

绑定的数据对象不必内联定义在模板里:

1
2
3
4
5
6
7
8
<div v-bind:class="classObject"></div>

data: {
classObject: {
active: true,
'text-danger': false
}
}

也可以在这里绑定一个返回对象的计算属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
<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:class,以应用一个 class 列表:

1
2
3
4
5
6
7
8
9
10
<div v-bind:class="[activeClass, errorClass]"></div>

data: {
activeClass: 'active',
errorClass: 'text-danger'
}

渲染为:

<div class="active text-danger"></div>

也可以根据条件来进行切换。使用三元运算符

1
<div v-bind:class="[true ? isActive : '',isActive2]" id="watch-example">

也可以将对象绑定和数组绑定混用

1
<div v-bind:class="[{  active: isActive  }, isActive2]">

绑定内联样式

对象语法

v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。

1
2
3
4
5
6
<div v-bind:style="{  color: activeColor, fontSize: fontSize + 'px'  }"></div>

data: {
activeColor: 'red',
fontSize: 30
}

通常直接绑定到一个样式对象更加清晰。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div v-bind:style="styleObject" id="watch-example">
<p>
{ { message } }
</p>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#watch-example",
data: {
message: "Hello",
styleObject:{
color:"red",
fontSize:"10px"
}
}
})
</script>

数组语法

v-bind:style 的数组语法可以将多个样式对象应用到同一个元素上:

1
<div v-bind:style="[baseStyles, overridingStyles]"></div>

自动添加前缀

v-bind:style使用需要特定前缀的CSS属性时,如transform。Vue会自动监听并添加对应前缀

多重值

可以为 style 绑定中的属性提供一个包含多个值的数组,常用于提供多个带前缀的值,例如:

1
<div :style="{  display: ['-webkit-box', '-ms-flexbox', 'flex']  }"></div>

这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染 display: flex

文章目录
  1. 1. 模板语法
    1. 1.1. 插值
      1. 1.1.1. 文本
      2. 1.1.2. 原始HTML
      3. 1.1.3. 特性
      4. 1.1.4. 使用JavaScript表达式
    2. 1.2. 指令
      1. 1.2.1. 参数
      2. 1.2.2. 修饰符
    3. 1.3. 缩写
  2. 2. 计算属性和观察者
    1. 2.1. 计算属性
      1. 2.1.1. 计算属性缓存 vs 方法
      2. 2.1.2. 计算属性 vs 侦听属性
      3. 2.1.3. 计算属性的 setter
    2. 2.2. 侦听器
  3. 3. Class 与 Style 绑定
    1. 3.1. 绑定 HTML Class
      1. 3.1.1. 对象语法
      2. 3.1.2. 数组语法
    2. 3.2. 绑定内联样式
      1. 3.2.1. 对象语法
      2. 3.2.2. 数组语法
      3. 3.2.3. 自动添加前缀
      4. 3.2.4. 多重值
|