Vue毕竟也是对JS的封装,只要是JS,免不了对DOM的操作。老外的教程和官网Vue的教程分类很不同,先来看看DOM操作吧。
- 双花括号 {{}} 叫做Interpolation或者 String Interpolation
- v-bind 绑定属性
- v-once 仅渲染一次
- v-html 输出原始HTML代码
- v-on 监听事件 给函数传入自定义参数
- 事件修饰符 event modifier - 阻止冒泡
- 事件修饰符 监听特定的键
- 在Vue表达式中直接使用JS代码
- v-model 双向绑定
- computed 计算属性
- watch 侦听属性
- 简化写法
- 更改CSS类
- 更改CSS样式
- 总结
双花括号 {{}}
双花括号就像是后端渲染的模板标签一样,对于其中的变量取值并且转换成字符串后进行显示,变量肯定也是有预先确定的命名空间。
由于类似于表达式求值,在Vue中双花括号的内容除了可以是data中的数据属性之外,还可以是methods中的方法名加上括号执行的结果,比如:
<div id="app">
<p>{{ title }}</p>
<p>{{ test1() }}</p>
</div>
<script>
new Vue({
el:"#app",
data:{
title:"Hello world!"
},
methods:{
test1:function () {
return "gugugugu"
}
}
})
</script>
花括号里边的内容写成this.title
和this.test1()
也是可以的,但不能写成data.title
,因为Vue会把属性和方法都设置到Vue实例上。
methods中的方法也可以返回data中的数据,比如:
<script>
new Vue({
el:"#app",
data:{
title:"Hello world!"
},
methods:{
test1:function () {
return this.title
}
}
})
</script>
只要函数的返回值可以转换成字符串就可以,比如显示刷新页面时候的时间:
<script>
new Vue({
el:"#app",
data:{
title:"Hello world!"
},
methods:{
test1:function () {
return new Date();
}
}
})
</script>
注意,花括号只能用在原本是HTML的标签内容的部分,而不能应用在属性上。
v-bind 绑定属性
指令v-bind
加上HTML的标准属性,然后设置值,可以将HTML的属性值与Vue实例的数据绑定。
比如想将一个链接的值设置为Vue实例内的一个URL字符串值:
<div id="app">
<p>{{ title }} - <a v-bind:href="url">{{ showUrl() }}</a></p>
</div>
<script>
new Vue({
el:"#app",
data:{
title:"conyli.cc",
url:"http://conyli.cc"
},
methods:{
showUrl:function () {
return this.title;
}
}
})
</script>
使用了v-bind
之后,虽然属性还是等于了一个字符串"url"
,但这个字符串此时已经不是字符串,而是表示Vue实例中的url属性。
有了绑定之后,不仅能使用双花括号操作标签的内容,还能使用绑定操作任意的标签属性。
v-once 仅渲染一次
这是一条单独的指令,对应的标签在生成页面的时候仅使用对应数据渲染一次,之后不再变动。
<div id="app">
<h1 style="text-align: center;" v-once>{{ title }}</h1>
<input type="text" v-on:input="changeTitle">
<p>{{ title }}</p>
</div>
<script>
new Vue({
el:"#app",
data:{
title:"conyli.cc",
url:"http://conyli.cc"
},
methods:{
changeTitle:function (event) {
this.title = event.target.value;
}
}
})
</script>
这里双向绑定了INPUT元素和P元素,输入之后P元素的内容会发生变化,但标题不会变动,只用最初数据渲染并且固定。可以发现双向绑定是自动去掉两端空格,中间重复空格只保留一个。
v-html 输出原始HTML代码而不转义
正常情况下花括号的内容会被转义,以避免恶意脚本。如果想输出HTML代码,则要使用指令v-html
,比较下边两个P元素:
<div id="app">
<p>{{ link }}</p>
<p v-html="link"></p>
</div>
<script>
new Vue({
el:"#app",
data:{
title:"conyli.cc",
url:"http://conyli.cc",
link: "<a href='http://conyli.cc'>conyli.cc</a>"
}
})
</script>
第一个P元素显示的就是转义后的字符串,而第二个P元素中就是HTML超链接,这说明v-html
可以不转义直接输出HTML代码。在使用的时候要当心。
v-on 监听事件
这个指令在最早的例子中使用过,监听input事件。v-on
之后可以监听任何JS原生的事件名称,然后值可以设置为methods中的处理方法,可以传入event对象。
做一个简单的计数器:
<div id="app">
<button v-on:click="add">Click me</button>
<p>{{ counter }}</p>
<p v-on:mousemove="update" style="height:100px;width: 200px;border: 1px solid red" >{{ x }} / {{ y }}</p>
</div>
<script>
new Vue({
el:"#app",
data:{
counter: 0,
x:0,
y:0
},
methods: {
add: function () {
this.counter++
},
update: function (event) {
this.x = event.clientX;
this.y = event.clientY;
}
}
})
</script>
这里给BUTTON元素设置了监听事件的add方法,每点一次按钮,就调用add方法让counter变量自增1,由于P元素的内容和counter变量绑定,所以会看到不断增加的数字。其实和v-bind一样,一旦对html属性应用指令,其字符串就变成了变量或者函数名称。
还给P元素设置了监听鼠标在其上移动的事件,动态的显示在框里鼠标的坐标。
牛逼之处还在于还可以自定义参数。如果想每次增加2,可以这么写:
<div id="app">
<button v-on:click="add(2)">Click me</button>
<p>{{ counter }}</p>
</div>
<script>
new Vue({
el:"#app",
data:{
counter: 0,
x:0,
y:0
},
methods: {
add: function (step) {
this.counter = this.counter + step;
}
}
})
</script>
在methods中的方法中也增加对应的参数,这样就传入了2当做步长,每一次增加2。如果在使用自定义参数的情况下还想使用event参数,需要在v-on的部分传入固定的一个变量叫做$event
,例子如下:
<div id="app">
<button v-on:click="add(2, $event)">Click me</button>
<p>{{ counter }}</p>
</div>
<script>
new Vue({
el:"#app",
data:{
counter: 0,
x:0,
y:0
},
methods: {
add: function (step, event) {
this.counter = this.counter + step;
console.log(event);
}
}
})
</script>
这样就能正确处理传入的事件了。对于methods中的所有方法,都可以如此来设置自定义参数。
控制事件 - event modifier
像刚才的例子改进一下,用一个大的Div套一个小的Div,希望小Div内部不发生事件。
代码如果用比较笨拙的方法实现,那么可以在小Div上监听同样的事件,然后阻止事件冒泡,这样外层就收不到事件:
<div id="app">
<div v-on:mousemove="move" class="outer">
<div v-on:mousemove="dummy" class="inner">
</div>
</div>
<p>{{x }} / {{ y }}</p>
</div>
<script>
new Vue({
el:"#app",
data:{
x:0,
y:0
},
methods:{
move: function (event) {
this.x = event.clientX;
this.y = event.clientY;
},
dummy: function (event) {
event.stopPropagation();
}
}
})
</script>
可以用更简单的方法做到,给指令加上一个.stop修饰符即可:
<div id="app">
<div v-on:mousemove="move" class="outer">
<div v-on:mousemove.stop class="inner">
</div>
</div>
<p>{{x }} / {{ y }}</p>
</div>
<script>
new Vue({
el:"#app",
data:{
x:0,
y:0
},
methods:{
move: function (event) {
this.x = event.clientX;
this.y = event.clientY;
}
}
})
</script>
这样就会在对应的元素上阻止该事件的发生。
监听特定的键,使用事件修饰符
<div id="app">
<div v-on:mousemove="move" class="outer">
<div v-on:mousemove.stop class="inner">
</div>
</div>
<p>{{x }} / {{ y }}</p>
<input type="text" v-on:keyup.enter.space="alertMe">
</div>
<script>
new Vue({
el:"#app",
data:{
x:0,
y:0
},
methods:{
move: function (event) {
this.x = event.clientX;
this.y = event.clientY;
},
alertMe: function (event) {
alert("Input end");
}
}
})
</script>
这里监听了keyup事件,然后指定了enter.space表示输入空格,只要监听到了,就触发事件。
使用原生JS代码
在所有被当做表达式解析的地方,可以直接写JS代码,其中的函数和变量名称,就相当于在Vue的实例一样,可以直接使用。
<div id="app">
<button v-on:click="count++">Click ++</button>
<button v-on:click="count--">Click --</button>
<p>{{ count }}</p>
<p>{{ count * 2 }}</p>
<p>{{ count < 10 ? "Less than 10": "Greater than 10" }}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
count: 0
},
methods: {
move: function (event) {
this.x = event.clientX;
this.y = event.clientY;
}
}
});
</script>
v-model 双向绑定
第一个例子中的绑定input事件还不是双向绑定,双向绑定使用v-model:
<div id="app">
<input type="text" v-model="name">
<p>{{ name }}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
name: "Saner"
},
methods: {
move: function (event) {
this.x = event.clientX;
this.y = event.clientY;
}
}
});
</script>
双向绑定是一个单独指令,将当前的元素的值直接绑定给data中的一个属性,同步变化。如果使用程序修改name的值,input框中的值也会变化。
computed 计算属性
考虑如下的情况:
<div id="app">
<button v-on:click="count++">Count++</button>
<button v-on:click="count--">Count--</button>
<button v-on:click="another++">Another++</button>
<button v-on:click="another--">Another--</button>
<p>{{ count }} | {{ another }}</p>
<p>{{ display() }} | {{computed_display }}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
count: 0,
another: 0
},
computed: {
computed_display:function () {
console.log("Computed value computed");
return this.count >= 5 ? "Count > 5" : "Count < 5";
}
},
methods: {
display: function () {
console.log("display() is executed");
return this.count >= 5 ? "Count > 5" : "Count < 5";
}
}
});
</script>
computed中的属性可以对应一个函数,但是不用像methods中的方法一样需要加括号调用,而是直接可以使用属性。
这两个有什么不一样的,答案是methods中的结果每次刷新dom或者刷新Vue实例的状态,都会执行,因为Vue不知道函数其中的内容是什么,只好每次求值并渲染。
但computed中的内容,会检查其内部和什么关联,当没有关联的时候,这个computed属性不会重新计算。
所以点击更改count属性的按钮时,两个方法都会执行,而点击更改another属性的按钮时,只会对display()求值并渲染,Vue知道computed中的内容与another没有关系,因此不会执行。
watch 侦听属性
<div id="app">
<button v-on:click="count++">Count++</button>
<button v-on:click="count--">Count--</button>
<button v-on:click="another++">Another++</button>
<button v-on:click="another--">Another--</button>
<p>{{ count }} | {{ another }}</p>
<p>{{ display() }} | {{computed_display }}</p>
</div>
<script>
new Vue({
el: "#app",
data: {
count: 0,
another: 0
},
computed: {
computed_display:function () {
console.log("Computed value computed");
return this.count >= 5 ? "Count > 5" : "Count < 5";
}
},
watch:{
count: function () {
let vm = this;
setTimeout(function () {
vm.count = 0;
}, 2000);
}
},
methods: {
display: function () {
console.log("display() is executed");
return this.count >= 5 ? "Count > 5" : "Count < 5";
}
}
});
</script>
与computed属性有些类似,watch是一个异步的侦听器。watch部分中的键名是已经存在的data中的属性名,只要这个属性一发生变化,对应的函数就会执行。
简化写法
经常使用的v-bind:
可以简写成:
;而v-on:
可以简写成@
:
<div id="app">
<p>{{ count }}</p>
<input type="text" :value="count">
<button @click="count++">Click</button>
</div>
<script>
new Vue({
el: "#app",
data:{
count:0
}
})
</script>
今后都采用简化的写法。
更改CSS类
更改CSS类有好几种做法:
<style>
.demo {
width: 100px;
height: 100px;
margin: 10px;
background-color: #dddddd;
}
.green {
background-color:green;
}
.blue {
background-color: blue;
}
.red {
background-color: red;
}
</style>
<div id="app">
<div class="demo" :class="{red:changeClass,blue:!changeClass}" @click="changeClass = !changeClass"></div>
<div class="demo" :class="divClass" @click="changeClass = !changeClass"></div>
<div class="demo" :class="color" @click="changeClass = !changeClass"></div>
<div class="demo" :class="[color,{green:changeClass}]" @click="changeClass = !changeClass"></div>
<input type="text" v-model="color">
</div>
<script>
new Vue({
el: "#app",
data:{
changeClass: false,
color: "red"
},
computed:{
divClass:function () {
return {
red:this.changeClass,
green:!this.changeClass
}
}
}
})
</script>
这里首先要知道的是可以有一个属性,然后再有一个v-bind的同名属性,对于css类来说,不会覆盖原来的类,只会控制新的类的增加和去除。
在第一个DIV中,绑定了一个对象,要始终记得,花括号内和绑定的属性内,都是相当于在Vue实例内部执行的表达式。第一个div中用red和blue名称对应了两个布尔值,在改变的时候,red或者blue类名就会应用到原来的类上,不会覆盖demo类。
第二个DIV中,是改用计算属性传递了一个对象,本质上和第一种方法类似
第三个DIV是比较直观,直接绑定color属性,输入color的名称就可以增加指定的类名上去。
第四个DIV是还可以传入一个数组,其中既可以有字符串名称,又可以有对象,都会被拆解应用到类名上,这里设置的意思是:默认就是red红色,不管如何点击。如果在input里去掉red字样,那么点击的时候就会在绿色和无色之间切换。
更改CSS样式
更改CSS样式靠的是绑定style属性,然后给这个属性传入对象,对象中的键是css属性名称,而值是css属性的值。
<div id="app">
<div class="demo" :style="styles"></div>
<input type="text" v-model="color">
<input type="text" v-model="width">
</div>
<script>
new Vue({
el: "#app",
data:{
changeClass: false,
color: "red",
width:200
},
computed:{
styles:function () {
return {
backgroundColor:this.color,
width:this.width+"px"
}
}
}
})
</script>
想修改何种属性,只要在对象中设置好键值对,然后传给绑定的style属性即可。在这个程序里,就可以通过输入颜色和宽度来控制Div元素的样式。
与类名一样,也可以通过数组的形式来修改css样式:
<div id="app">
<div class="demo" :style="styles"></div>
<div class="demo" :style="[styles, style2, {margin: this.height/5 + 'px'}]"></div>
<input type="text" v-model="color">
<input type="text" v-model="width">
<input type="text" v-model="height">
</div>
<script>
new Vue({
el: "#app",
data:{
changeClass: false,
color: "red",
width:200,
height:200
},
computed:{
styles:function () {
return {
backgroundColor:this.color,
width:this.width+"px"
}
},
style2:function () {
return {
height:this.height+"px"
}
}
}
})
</script>
第二个Div元素的样式就同时通过两个对象和一个等于高度五分之一的margin来动态控制。
总结
初看此处的部分有些凌乱,后来我总结了一下,由于是操作DOM,不外乎针对每个元素的所有能控制的属性进行控制,有如下这么几方面:
- 元素的内容,由花括号的表达式来修改。花括号普通情况下输出转义后的字符串,还可以使用v-html输入不转义的HTML代码,v-once仅渲染一次
- 元素的属性,由v-bind:来绑定修改,绑定后的属性值双引号里边的内容不再是字符串,而是当做Vue内部的表达式解析。这里边又分为单一的值属性和类似于CSS类和Style的多个值属性或者需要对象类别的属性,可以传入对象
- 事件,由v-on:来绑定修改,还可以使用事件修饰符来进行具体控制
- 双向绑定,Vue中的属性变化,对应的值也变化;值变化,Vue实例中的属性也变化,常用于input框,用一个单独的v-model指令即可。
- computed计算属性和watch侦听属性,有些类似于事件。computed属性能减少不必要的调用方法,watch是异步的,比较方便。
- 更改CSS类和CSS样式,Vue这里特别做了增强,除了绑定单一属性,还可以绑定数组和对象,便于传递多个设置。
通过这些方法,就可以操控Dom上任何一个元素的内容,各种属性,类和样式,以及事件,这就是Vue操作Dom的方式,也是Vue使用的基础。