Vue事件绑定、计算属性、表单输入绑定和自定义组件
一、事件绑定
1.HTML元素事件绑定
事件绑定就是在HTML元素中,通过v-on或者 @ 绑定事件。
事件代码可以直接放到v-on后面,也可以写成一个函数。
测试如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id="app">
<p>{{count}}</p>
<button v-on:click="count+=1">加一</button>
<button @click="decrease">减一</button>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
count:0
},
methods:{
// 函数简写形式
decrease(){
this.count -= 1
}
}
})
</script>
显示:
可以达到控制数的增减的效果。
同时,可以对函数传参,如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id="app">
<p>{{count}}</p>
<button v-on:click="count+=1">加一</button>
<button @click="decrease(2)">减一</button>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
count:0
},
methods:{
// 函数简写形式
decrease(value){
this.count -= value
}
}
})
</script>
显示:
2.event参数
如果在事件处理函数中,想要获取原生的DOM事件,那么在调用的时候可以在html代码中传递一个$event
参数。
参数测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id="app">
<p>{{count}}</p>
<button v-on:click="count+=1">加一</button>
<button @click="decrease(2,$event)">减一</button>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
count:0
},
methods:{
// 函数简写形式
decrease(value,event){
this.count -= value
console.log(event)
}
}
})
</script>
显示:
显然,$event
参数表示的是与事件(鼠标点击)相关的一些参数和属性。
再次测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id="app">
<p>{{count}}</p>
<button v-on:click="count+=1">加一</button>
<button @click="decrease(2,$event)" name="Corley" value="Vue">减一</button>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
count:0
},
methods:{
// 函数简写形式
decrease(value,event){
this.count -= value
console.log(event.target.value)
console.log(event.target.name)
}
}
})
</script>
显示:
显然,event参数携带了点击按钮事件的很多信息,还包括了Button的相关属性。
二、计算属性和监听属性
1.计算属性computed
一般情况下属性都是放到data中的,但是有些属性可能是需要经过一些逻辑计算后才能得出来,那么我们可以把这类属性变成计算属性。
进行测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id="app">
<label for="">长:</label>
<input type="number" name="length" v-model:value="length">
<label for="">宽:</label>
<input type="number" name="width" v-model:value="width">
<label for="">面积:</label>
<input type="number" name="area" v-bind:value="area" readonly>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
length:0,
width:0
},
// 计算属性
computed:{
area:function(){
return this.length * this.width
}
}
})
</script>
显示:
显然,面积随着长和宽的变化而动态变化。
其中,v-model是双向绑定,绑定了Vue对象中的data数据。
在上例中,v-model
将input标签的value与data中的length绑定,即保持一致,也便于后边计算面积时HTML表单元素和属性的数据同步获得即时数据。
v-model:value="length"
可以简写成v-model="length"
,效果是一样的。
可能你会觉得这个计算属性与函数好像有点重复。实际上,计算属性更加智能,它是基于它们的响应式依赖进行缓存的,也就是说只要相关依赖(比如以上例子中的area)没有发生改变,那么这个计算属性的函数不会重新执行,而是直接返回之前的值。这个缓存功能让计算属性访问更加高效。
2.计算属性的set方法
计算属性默认只有get,不过在需要时也可以提供一个set,但是提供了set就必须要提供get方法。
get方法测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id="app">
<div>
<label for="">省:</label>
<input type="text" v-model:value="province">
</div>
<div>
<label for="">市:</label>
<input type="text" v-model:value="city">
</div>
<div>
<label for="">区:</label>
<input type="text" v-model:value="district">
</div>
<div>
<label for="">详细地址:</label>
<input type="text" v-model:value="address" readonly>
</div>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
province:'',
city:'',
district:'',
},
// 计算属性
computed:{
address:{
get:function(){
var result = ""
if(this.province){
result = this.province + "省"
}
if(this.city){
result += this.city + "市"
}
if(this.district){
result += this.district + "区"
}
return result
}
}
}
})
</script>
显示:
增加set()
方法测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id="app">
<div>
<label for="">省:</label>
<input type="text" v-model:value="province">
</div>
<div>
<label for="">市:</label>
<input type="text" v-model:value="city">
</div>
<div>
<label for="">区:</label>
<input type="text" v-model:value="district">
</div>
<div>
<label for="">详细地址:</label>
<input type="text" v-model:value="address">
</div>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
province:'',
city:'',
district:'',
},
// 计算属性
computed:{
address:{
get:function(){
var result = ""
if(this.province){
result = this.province + "省"
}
if(this.city){
result += this.city + "市"
}
if(this.district){
result += this.district + "区"
}
return result
},
set:function(value){
// 用/包含来表明这是JavaScript中的正则表达式
var result = value.split(/省|市|区/)
if(result && result.length > 0){
this.province = result[0]
}
if(result && result.length > 1){
this.city = result[1]
}
if(result && result.length > 2){
this.district = result[2]
}
}
}
}
})
</script>
显示:
用 / 包含来表明这是JavaScript中的正则表达式,用来分割匹配字符串中的省、市、区。
注意:
get()
和set()
方法是不能重命名的,否则不能达到效果。
3.监听属性watch
监听属性可以针对某个属性进行监听,只要这个属性的值发生改变了,那么就会执行相应的函数。
测试如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id="app">
<label>搜索:</label>
<input type="text" v-model:value="keyword">
<p>结果:</p>
<p>{{result}}</p>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
keyword:'',
result:''
},
// 监听属性
watch:{
keyword:function(newvalue,oldvalue){
this.result = '加载中...'
// 定时器
setTimeout(() => {
this.result = '搜索结果:' + newvalue
}, 1000);
}
}
})
</script>
显示:
这个效果可以在一定程度上模拟百度搜索时下拉显示推荐搜索内容的效果。
三、表单输入绑定
1.input标签输入绑定
v-model指定可以实现表单值与属性的双向绑定,即表单元素中更改了值会自动的更新属性中的值,属性中的值更新了会自动更新表单中的值。
v-model在内部为不同的输入类型使用不同的属性并抛出不同的事件:
- text和textarea元素使用value属性和input事件;
- checkbox和radio使用checked属性和change事件;
- select字段使用value属性和change事件。
下面分别进行测试:
- text输入绑定测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id="app">
<input type="text" v-model:value="message" placeholder="请输入...">
<p>输入的内容是:{{message}}</p>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
message:''
},
})
</script>
显示:
- textarea测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id="app">
<textarea name="" v-model:value="message" id="" cols="30" rows="10"></textarea>
<p>输入的内容是:{{message}}</p>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
message:''
},
})
</script>
显示:
- checkbox测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id='app'>
<input type="checkbox" value="Python" v-model="checkedNames">
<label for="">Python</label>
<input type="checkbox" value="Java" v-model="checkedNames">
<label for="">Java</label>
<input type="checkbox" value="PHP" v-model="checkedNames">
<label for="">PHP</label>
<br>
<span>Checked names: {{checkedNames}}</span>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
checkedNames:[]
},
})
</script>
显示:
- radio测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id='app'>
<input type="radio" value="男" v-model="gender">
<label>男</label>
<br>
<input type="radio" value="女" v-model="gender">
<label>女</label>
<br>
<span>Picked: {{gender}}</span>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
gender:''
},
})
</script>
显示:
- select测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id='app'>
<select v-model="selected">
<option disabled value="">请选择</option>
<option value="1">A</option>
<option>B</option>
<option value="33">C</option>
</select>
<span>Selected: {{selected}}</span>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
selected:''
},
})
</script>
显示:
可以看出:
如果option标签有value值,被绑定的就是value值;
如果没有value值,被绑定的就是选项值,即对应的文本值。
2.修饰符
.lazy
在默认情况下,v-model在每次input事件触发后将输入框的值与数据进行同步 。
如果不想实时修改、而是光标移开之后再修改,可以添加lazy修饰符,从而转变为使用change事件进行同步,可以称之为懒加载。
测试如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id='app'>
<!-- 在"change"时而非"input"时更新,即光标移除input输入框的时候更新 -->
<input type="text" v-model:value.lazy="message" placeholder="请输入...">
<p>输入的内容是:{{message}}</p></p>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
message:''
},
})
</script>
显示:
v-model:value.lazy="message"
可以简写为v-model.lazy="message"
。
.number
如果想自动将用户的输入值转为数值类型,可以给v-model添加number修饰符。
.number测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id='app'>
<input type="text" v-model:value.number="number" placeholder="请输入...">
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
number:0
},
})
</script>
显示:
显然,输入的非数字字符都被过滤掉,只剩下数字。
这通常很有用,因为即使在type="number"
时,HTML输入元素的值也总会返回字符串。如果这个值无法被parseFloat()
解析,则会返回原始的值。
.trim
如果要自动过滤用户输入的首尾空白字符,可以给v-model添加trim修饰符。
.trim测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id='app'>
<input type="text" v-model:value.trim="message" placeholder="请输入...">
<p>{{message}}</p>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
message:''
},
watch:{
message:function(newvalue,oldvalue){
console.log(this.message)
}
}
})
</script>
显示:
四、自定义组件的基本使用
有时候有一组html结构的代码,并且还可能绑定了事件,这段代码可能有多个地方都被使用到了,如果都通过拷贝,会导致很多重复的代码,包括事件部分的代码都是重复的。
这个时候我们可以把这些代码封装成一个组件,以后在使用的时候就跟使用普通的html元素一样,拿过来用就可以了,这就是自定义组件。
自定义组件的基本使用测试如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue模板语法</title>
</head>
<body>
<div id='app'>
<button-click></button-click>
<button-click></button-click>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('button-click',{
template:'<button @click="count+=1">点击了{{count}}次</button>',
data:function(){
return {
count: 0
}
}
})
new Vue({
el:'#app',
data:{
},
})
</script>
显示:
显然,自定义组件可以正常使用,并且之间不会相互影响;
同时,大大提高了代码的复用性。
以上我们创建了一个叫做button-click的组件,这个组件实现了记录点击次数的功能。后期如果我们想要使用,就直接通过button-click使用就可以了。
因为组件是可复用的Vue实例,所以它们与new Vue接收相同的选项,包括data、computed、watch、methods以及生命周期钩子等,仅有的例外是像el这样根实例特有的选项。
同时需要注意:
组件中的data必须为一个函数。