绑定
使用 Vue.js,从命令式编程走向声明式编程。
以设置 DOM 数据为例,使用命令式的做法:找到DOM项目 ➡️设置值。
使用声明式,只需要一步:直接声明绑定。
使用声明编程后,编写此类代码的好处:
- 不必访问 DOM API 即可修改 DOM;
- 响应式的风格:不但第一次给设置好,当绑定的数据值变化了,DOM 显示会跟着变化。
如下代码展示我提到的绑定的两个特征:
<div id="app">{{value}}</div>
<script>
new Vue({
el: '#app',
data(){
return {value:42}
},
mounted(){
setTimeout(this.a,1000)
},
methods:{
a(){
this.value++
console.log(this.value)
setTimeout(this.a,1000)
}
}
})
</script>
首先,在插值的地方使用形如 {{}}
的符号,声明此值绑定到一个成员变量,Vue 就会知道:需要从对应 Vue 实例中的 data
函数返回的对象内查找 value,并使用它的值来填充占位。
DOM 的标签会跟着 value 的变化而变化。
绑定包括数据绑定、事件绑定、元素绑定。
🐼 数据绑定
插入值绑定
具体说来,就是把实例内的数据成员绑定到插入值指定的位置。采用Mustache 语法,即 {{}}
。
插入值绑定将会把数据对象上的属性值插入到 Mustache 指示的位置,且绑定的数据对象的变化会导致插值的变化。
如果不希望后续的变化修改插值,可以使用 v-once
指令。就是修改一行代码 <div id="app">{{value}}</div>
为:<div id="app" v-once>{{value}}</div>
在 Mustache 内还可以使用 JavaScript 表达式
,比如:{{ value + 1 }}
。
但是每个绑定都只能包含单个表达式。语句或者多个表达式是不可以的。
想要绑定到属性,就得使用指令 v-bind
:
<input v-bind:value="value">
🥑 针对 class 的情况
针对标签属性 class,v-bind 可以直接传入一个对象作为属性值,像是这样:
<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
如果 isActive 为 true,那么 active 作为字符串拼接结果的一部分;如果 hasError 为 true,则 text-danger 为字符串拼接结果的一部分。
因此:
data: {
isActive: true,
hasError: false
}
得到的渲染结果为:
<div class="active"></div>
也可以传入一个数组作为 class 属性的值:
<div v-bind:class="[active,text-danger]"></div>
得到的渲染结果为:
<div class="active text-danger"></div>
🍐 针对 style 的情况
也可以如针对 class 那样,传入对象或者数组,对象就是一个 style 对象,数组则是多个 style 对象。
🌰:
<div v-bind:style="styleObject">abc</div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
渲染出来的结果为:
<div style="color:red;fontSize:13px; ">abc</div>
完整演示对象和数组的代码为:
<div id="app">
<!--方法一-->
<div style="color:red;fontSize:13px;">abc</div>
<!--方法二-->
<div v-bind:style="[s1,s2]">abc</div>
<!--方法三-->
<div v-bind:style="styleObject">abc</div>
</div>
<script>
var a= new Vue({
el: '#app',
data: {
styleObject: {
color: 'red',
fontSize: '13px'
},
s1: {
color: 'red',
},
s2: {
fontSize: '13px'
}
}
})
</script>
🐻 事件绑定
指令 v-on 可以监听 DOM 事件。
🌰:
显示一个按钮,点击此按钮会在控制台打印 “BUTTON”:
<div id="app">
<button v-on:click="who">who</button>
</div>
<script>
var a= new Vue({
el: '#app',
methods: {
who: function (event) {
console.log(event.target.tagName)
}
}
})
</script>
指令 v-on 会把参数(click)指定的事件挂接到属性值指定的方法(who)上。方法 who 的参数 event 为原生的 JavaScript 事件对象。
指令 v-on 可以使用 修饰符
。
可以选这些修饰符:
- .stop
- .prevent
- .capture
- .self
还有一类特别的修饰符用于 键盘事件
的修饰:
- .enter
- .tab
- .delete
- .esc
- .space
- .up
- .down
- .left
- .right
.keyup.enter //表示侦听enter键的keyup事件。
也可以在 keyup 修饰符后跟着一个数字表示按键的 ASCII 码
:
.13 等同于.enter
🐰 元素绑定
不但可以做属性绑定,元素也可以绑定的。比如根据表达式条件的不同来绑定不同的元素,或者循环绑定元素。
🥑 v-if
指令 v-if 可以完成条件化的元素绑定。比如:
<h1 v-if="false">h1</h1>
<h2 v-else>h2</h2>
当然,如果不必要,v-else 是可以不写的。
如果需要条件化绑定的是一组元素,可以使用 <template>
来打包分组:
<template v-if="true">
<h1>h1</h1>
<p>big title</p>
</template>
<template v-else>
<h1>h2</h1>
<p>second title</p>
</template>
有一个叫做 v-show 的指令,可以根据表达式的真假值来决定是否显示元素。
但是,即使表达式是假值,元素依然会绑定到DOM中,只是并不显示:
<h1 v-show="false">h1</h1>
因此,它并不是一个元素绑定指令。
🍐 v-for
指令 v-for 基于一个数组
渲染一组元素。这个指令的表达式使用特殊的语法,形式为:
- item in items 或者 item of items,
- 或者 (item, index) in items,如果你需要循环索引的话。
🌰:
<div id="app"><ul>
<li v-for="(item, index) in items">{{ item }},{{ index }}</li>
</ul></div>
<script>
var a= new Vue({
el: '#app',
data(){return {items :[1,2,3]} }
}
)
</script>
输出:
1,0
2,1
3,2
指令 v-for 也可以对对象
进行迭代,每个迭代出来的项目就是一个属性/值对:
<div id="app"><ul>
<li v-for="(v,k) in person">{{ k }}:{{ v }}</li>
</ul></div>
<script>
var a= new Vue({
el: '#app',
data(){return {
person :{
name:'frodo',
group:'ring fellow'
}
}
}}
)
</script>
指令 v-for 也可以对整数
迭代,等于循环整数次:
<div id="app"><ul>
<li v-for="v in 3">{{ v }}</li>
</ul></div>
<script>
var a= new Vue({
el: '#app'
}
)
</script>
数组的响应化
在 v-for 的案例中我们对一个数组(items)进行迭代,创建了元素绑定。现在或许有人会怀疑:如果我修改了数组,是否也可以因此响应式地影响到 DOM 呢。答案是可能。
🌰:其中添加了一个定时器,每秒钟调用一个函数,函数内有不同的数组方法:
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app"><ul>
<li v-for="item in items">{{ item }}</li>
</ul></div>
<script>
var a= new Vue({
el: '#app',
mounted(){
this.funcs[0] = this.b
this.funcs[1] = this.c
this.funcs[2] = this.d
this.funcs[3] = this.e
this.funcs[4] = this.f
this.funcs[5] = this.g
this.funcs[6] = this.h
this.funcs[7] = this.i
this.funcs[8] = this.j
setTimeout(this.a,1000)
},
data(){return {
items :[1,2,3],
funcs:[],
funcIndex : 0
}},
methods:{
a(){
this.funcs[this.funcIndex]()
this.funcIndex++
if (this.funcIndex < this.funcs.length)
setTimeout(this.a,1000)
},
b(){
this.items.push(4)
},
c(){
this.items.pop()
},
d(){
this.items.shift()
},
e(){
this.items.unshift(1)
},
f(){
this.items.splice(1,1)
},
g(){
this.items.reverse()
},
h(){
this.items.sort()
},
i(){
// this.items[0] = 111
Vue.set(this.items,0,111)
},
j(){
// this.items.length = 1
this.items.splice(1,1)
}
}
})
</script>
测试表明,对以下方法的调用,Vue 确实会做响应的修改:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
但是需要留意最后两个函数,i() , j(), 其中的 i() 函数内如果使用:
this.items[0] = 111
并不会引发响应变化。这是 vue 的一个限制,如果希望修改数组项并因此响应化的更新 DOM,那么需要这样做:
Vue.set(this.items,0,111)
另外一个是数组的 length 属性,修改它 DOM 并不会跟随变化。如果你的本意是删除一个元素,可以用:this.items.splice(1,1)
来做替代。
绑定控件
控件绑定常常涉及到双向绑定,此时使用 v-model
让它更加简单。
<div id="app">
<label><input type="checkbox" v-model="checked">v-model</label><br/>
<label for="checkbox">{{ checked }}</label>
</div>
<script>
var a= new Vue({
el: '#app',
data(){return {checked : true} }
}
)
</script>
正如我们已经看到的:v-model 是 v-bind 和 v-on 的语法糖。但是这个语法糖确实很甜。
具体的控件的绑定
🍵 text
<input type="text" v-model="message">
🥛 checkbox
- 在单个 checkbox 的情况下:
<input type="checkbox" v-model="checked">
- 在多个 checkbox 的情况下:
<input type="checkbox" value="1" v-model="checks">
<input type="checkbox" value="2" v-model="checks">
<input type="checkbox" value="3" v-model="checks">
🍹 radio
此控件可以成组使用,组内互斥选择,最后只能选择一项目:
<div id="app">
<input type="radio" value="1" v-model="which">
<input type="radio" value="2" v-model="which">
<span>{{ which }}</span>
</div>
<script>
var a= new Vue({
el: '#app',
data(){return {which :"2"} }
}
)
</script>
☕️ select
此控件允许多选和单选。
- 在 单选 的情况下,v-model 指向到单项数据:
<div id="app">
<select v-model="which" >
<option which>1</option>
<option>2</option>
<option>3</option>
</select>
<span>which: {{ which }}</span>
</div>
<script>
var a= new Vue({
el: '#app',
data(){return {which :"2"} }
}
)
</script>
- 多选 情况下,v-model 对应的是一个数组:
<div id="app">
<select v-model="which" multiple>
<option>1</option>
<option>2</option>
<option>3</option>
</select>
<span>which: {{ which }}</span>
</div>
<script>
var a= new Vue({
el: '#app',
data(){return {which :["2","3"] } }
}
)
</script>
🥤 textarea
作为多行文本区的 textarea,可以这样绑定:
<textarea v-model="msg"></textarea>
🌰:
<div id="app">
<textarea v-model="msg" placeholder="input some lines"></textarea>
<p style="white-space: pre">message:<br>{{ msg }}</p>
</div>
<script>
new Vue({
el:'#app',
data:{msg:''}
})
</script>
可以在文本区内输入多行文本,内容会照搬到 p 标签内。
🔗: