3.Vue组件的属性和方法

属性与方法基础

组件的数据都放在了data选项中,Vue组件的data选项是一个函数,组件在被创建时会调用此函数来构建响应性的数据系统。

属性基础

在Vue组件中定义的属性数据,我们可以直接使用组件来调用,这是因为Vue在组织数据时,任何定义的属性都会暴露在组件中。实际上,这些属性数据是存储在组件的$data对象中的,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
const App = {
data(){
return{
conunt:111,
}
}
}
// 创建组件并获取组件实例
let instance = Vue.createApp(App).mount("#Application")
// 可以获取到组件中的data数据
console.log(instance.conunt)
// 可以获取到组件中的data数据
console.log(instance.$data.conunt)

运行上面的代码,通过控制台可以看出,使用组件实例直接获取属性与使用$data的方法获取属性的结果是一样的,本质上访问的是同一块数据。无论那种方式对数据进行修改后,两种获取方式获取到的值都会发生改变

1
2
3
4
5
// 修改属性
instance.conunt = 555
// 两种获取到的值都是555
console.log(instance.conunt)
console.log(instance.$data.conunt)

方法基础

组件的方法被定义在methods选项中,我们在实现组件的方法时,可以放心地在其中使用this 关键字,Vue自动将其绑定到当前组件实例本身。例如,添加一个add方法

1
2
3
4
5
6
7
8
          methods:{
add(){
this.conunt ++
}
}

instance.add()
console.log(instance.conunt) // 112

计算属性和侦听器

计算属性

前面章节中的示例代码,我们定义的属性都是存储属性 ,与之相对的还有计算属性

判断组件中conunt大于10,输出大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const App = {
data(){
return{
conunt:111,
}
},
// computed定义计算属性
computed:{
type(){
return this.conunt > 10 ? "大" : "小"
}
},
methods:{
add(){
this.conunt ++
}
}

}
// 创建组件并获取组件实例
let instance = Vue.createApp(App).mount("#Application")
console.log(instance.type) // 大
instance.conunt=1
console.log(instance.type) // 小

计算属性的强大在于,当会影响其值的存储属性发生变化时,计算属性也会同步进行更新,如果元素绑定了计算属性,其也会同步进行更新。

1
2
3
4
<div>{{type}}</div>
<button @click="add">Add</button>

// instance.conunt=9

点击button按钮,conunt大于10时,页面对应的小会变成大

使用计算属性还是函数

1
2
3
4
5
6
7
8
methods:{
add(){
this.conunt ++
},
typeFunc(){
return this.conunt > 10 ? "大" : "小"
}
}

使用函数或计算属性的结果完全一致,事实上,计算属性基于其依赖的存储属性的值的变化而重新计算的,计算完成后会其结果会被缓存,下次访问计算属性时,其依赖的值没有发生变化,其内的逻辑代码就不会重复执行。函数则不同,每次访问其都会重新执行函数内容得到结果。

根据是否需要缓存,来选择计算属性还是函数。

计算属性的赋值

存储属性主要用于数据的存取,计算属性只用来取值,不会用来存值。因此计算属性默认提供的取值方法get

这并不代表计算属性不支持赋值,计算属性也可以通过赋值进行存取数据操作,存数据的方法我们需要手动实现,通常称之为set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// computed定义计算属性
computed:{
type:{
get(){
return this.conunt > 10 ? "大" : "小"
},
set(newValue){
if (newValue == "大"){
this.conunt=121
}else{
this.conunt=0
}
}
}
},

赋值时会调用我们定义的set方法,从而实现对存储属性进行赋值。

1
2
3
4
5
6
7
   let instance = Vue.createApp(App).mount("#Application")

// 可以获取到组件中的data数据
console.log(instance.conunt) // 111
console.log(instance.type) // 大
instance.type="小" // 对计算属性进行修改
console.log(instance.conunt) // 0

如果一个计算属性只实现了get 方法没有实现set方法,则在使用时只能进行取值操作

属性侦听器

属性侦听时Vue非常强大的功能之一,使用属性侦听可以方便的监听某个属性的变化,以完成复杂的业务逻辑。

例如,我们使用搜索引擎在搜索框中写入关键字后,网页上会自动关联一些关键词供用户选择。

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 lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>输入字符超过10时,就会有警告弹窗</title>
<script src="https://unpkg.com/vue@3.2.47/dist/vue.global.js"></script>
</head>
<body>
<div id="Application">
<input v-model="searchText"/>
</div>
<script>
const App = {
data(){
return {
searchText : "",
}
},
watch:{
searchText(oldValue,newValue){
if (newValue.length > 10){
alert('文本太长了')
}
}
}
}
Vue.createApp(App).mount("#Application")
</script>
</body>
</html>

进行函数限流

在工程开发中,限流是一个非常重要的概念。

场景一:单击某个按钮会从后端服务器发起数据请求,在数据请求回来之前,用户额外的单击是无效且消耗性能的。

场景二:某个按钮会导致页面的更新,我们需要限制用户频繁操作。

手动实现一个简易的限流函数

功能:单击按钮打印方法输出当前时间,要求这个按钮两次事件触发间隔不能小于2秒

方法:思路是用一个变量来控制按钮是否可以触发,触发时对此变量进行修改,2秒后将变量值还原

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/vue@3.2.47/dist/vue.global.js"></script>
</head>
<body>
<div id="Application">
<button @click="click">刷新</button>
</div>
<script>
const App = {
data(){
return{
throttle:false
}
},
methods:{
click(){
if (!this.throttle){
console.log(Date())
}else{
return
}
this.throttle=true
setTimeout(() => {
this.throttle = false
},2000);
}
}
}
Vue.createApp(App).mount("#Application")
</script>
</body>
</html>

使用Lodash库进行函数限流

有许多第三方工具库都提供了函数限流功能,它们强大易用,Lodash库就是其中之一

简介:

Lodash 是一个 JavaScript 实用工具库,提供一致性,及模块化、性能和配件等功能。

Lodash 消除了处理数组的麻烦,从而简化了 JavaScript、 数字、对象、字符串等。

Lodash 库中提供了debounce函数来进行方法的调用限流,要使用它,首先需要引入Lodas库,代码如下:

1
<script src="https://unpkg.com/lodash@4.17.20/lodash.min.js"></script>

修改代码如下

1
2
3
4
5
6
7
8
const App = {
methods:{
click:_.debounce(function(){
console.log(Date())
},2000)
}
}
Vue.createApp(App).mount("#Application")

表单数据的双向绑定

文本输入框

文本输入框的数据绑定:直接使用v-model指令设置即可

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/vue@3.2.47/dist/vue.global.js"></script>
</head>
<body>
<div id="Application">
<input v-model="textField">
<p>文本输入框内容{{textField}}</p>
</div>
<script>
const App = {
data(){
return{
textField:''
}
},
}
Vue.createApp(App).mount("#Application")
</script>

</body>
</html>

多行文本输入区域

多行文本可以使用textarea标签来实现,textarea数据绑定方式和input一样

1
2
<textarea v-model="textField" cols="30" rows="10"></textarea>
<p>多行文本输入框内容{{textField}}</p>

复选框与单选框

input类型设置为checkbox时,其就会以复选框的样式进行渲染。如果只有一个复选框,在使用v-model指令进行数据绑定时,可以直接将其绑定为布尔值。

1
2
3
4
5
6
7
8
9
10
<input type="checkbox" v-model="checkbox">
<p>{{checkbox}}</p>


data(){
return{
textField:'',
checkbox:'',
}
},

复选框一般都是成组出现的,这时我们可以为每一个复选框元素设置一个特殊的值。通过数组属性的绑定来获取每个复选框是否被选中,如果被选中,则数组中会存在其所关联的值;如果没有被选中,则数组中其关联的值会被删除掉。

1
2
3
4
<input type="checkbox" value="足球" v-model="checkLIst">足球
<input type="checkbox" value="篮球" v-model="checkLIst">篮球
<input type="checkbox" value="排球" v-model="checkLIst">排球
<p>{{checkLIst}}</p>

单选框的数据绑定与复选框类似,对每一个单选框元素都可以设置一个特殊的值,并将同一组单选框绑定到同一个属性中即可

1
2
3
<input type="radio" value="男" v-model="sex">
<input type="radio" value="女" v-model="sex">
<p>{{sex}}</p>

vue代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
<script>
const App = {
data(){
return{
textField:'',
checkbox:'',
checkLIst:[]
}
},
}
Vue.createApp(App).mount("#Application")
</script>

示例图

选择列表

单选的选择列表,可以直接绑定到Vue组件的一个属性上

多选的选择列表,可以将其绑定到数组属性上

1
2
3
4
5
<select v-model="select">
<option></option>
<option></option>
</select>
<p>{{select}}</p>

select 标签内部,option 标签用来定义一个选项,若要支持多选操作,则只需要为其添加上multiple 属性即可

1
2
3
4
5
6
<select v-model="selectList" multiple>
<option>篮球</option>
<option>足球</option>
<option>排球</option>
</select>
<p>{{selectList}}</p>

vue示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
const App = {
data(){
return{
textField:'',
checkbox:'',
checkLIst:[],
sex:'',
select:'',
selectList:[]
}
},
}
Vue.createApp(App).mount("#Application")
</script>

两个常用的修饰符

在对表单进行数据绑定时,可以使用修饰符来控制绑定指令的一些行为。比较常用的修饰符有lazytrim

lazy修饰符类似于属性的懒加载。

当v-model对文本输入框进行绑定时,输入框发生变化都会同步修改对应属性的值。某些业务情况下,我们并不需要实时关注输入框文字的变化,只需要用户输入完成后在关注值的变化,这时就可以使用lazy修饰符

1
2
<input v-model.lazy="textField">
<p>文本输入框内容{{textField}}</p>

运行上面代码,只有用户输入完成,即输入框失去焦点后,段落中的textField才会同步输入框中的textField

trim修饰符的作用是将绑定的文本数据的首尾空格去掉 ,很多应用场景,用户输入的数据需要提交给后端处理

1
2
<input v-model.trim="textField">
<p>文本输入框内容{{textField}}文本输入框内容</p>

样式绑定

在Vue中对class属性的数据绑定做了增强,可以方便通过布尔值控制其设置的样式是否被选用

HTML标签绑定Class属性

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/vue@3.2.47/dist/vue.global.js"></script>
<style>
.red{
color: red;
}
.blue{
color: blue;
}
</style>
</head>
<body>
<div id="Application">
<div :class="{blue:isBlue,red:isRed}">
示例文案
</div>
</div>
<script>
const App = {
data(){
return{
isBlue:true,
isRed:false
}
}
}
Vue.createApp(App).mount("#Application")
</script>
</body>
</html>

以上代码所示,其中div元素的class属性的值会根据isBlue,isRed属性的值而改变。如果设置对象有多个属性的值都为true,则都会被添加class属性中。

在实际开发中,不一定用内联的方式为class绑定控制对象,可以直接将其设置为一个Vue组件中的数据对象,修改代码如下

1
2
3
<div :class="style">
示例文案
</div>
1
2
3
4
5
6
7
8
9
10
        const App = {
data(){
return{
style:{
blue:true,
red:false
}
}
}
// 将样式对象作为计算属性返回,使用这种方式进行组件样式的控制非常高效

Vue还支持用数组对象来控制class属性

1
2
3
<div :class="[blueClass,redClass]">
示例文案
</div>
1
2
3
4
5
6
data(){
return{
redClass:'red',
blueClass:"blue",
}
}

绑定内联样式

内联样式是指通过HTML元素的style属性来设置样式,style属性可以直接通过javascript对象来设置样式,我们也可以通过内部使用Vue属性

1
2
3
<div :style="{color: color,fontSize: font}">
示例文案
</div>
1
2
3
4
5
6
data(){
return{
color:'green',
font:'50px',
}
}

需要注意,外部定义CSS属性在命名时,多采用-font-size,内联命名时多采用驼峰命名法如fontSize。直接绑定对象属性在实际开发中更加常用。

范例:实现一个功能完整的用户注册页面

搭建用户注册页面

搭建用户注册页面,页面由标题,信息输入框,偏好设置,确认按钮

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="container" id="Application">
<div class="container">
<div class="subTitle">加入我们,一起创造美好世界</div>
<h1 class="title">创建你的账号</h1>
<div v-for="(item,index) in fields" class="inputContainer">
<div class="field">{{item.title}} <span v-if="item.required" style="color: red;">*</span></div>
<input class="input" type="item.type">
<div class="tip" v-if="index == 2">请确认密码需要大于6位</div>
</div>

<div class="subContainer">
<div class="setting">偏好设置</div>
<input class="checkbox" type="checkbox"><label class="label">接收更新邮件</label>
</div>
<button class="btn">创建账号</button>
</div>
</div>

Vue

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
<script>
const App={
data(){
return{
fields:[
{
title:'用户名',
required:true,
type:'text'
},
{
title:'邮箱地址',
required:true,
type:'text'
},
{
title:'密码',
required:true,
type:'password'
},
]
}
}
}
Vue.createApp(App).mount("#Application")
</script>

CSS

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
<style>
.container {
margin: 0 auto;
margin-top: 70px;
text-align: center;
width: 300px;
}
.subTitle {
color: gray;
font-size: 14px;
}
.title {
font-size: 45px;
}
.input {
width: 90%;
}
.inputContainer {
text-align: left;
margin-bottom: 20px;
}
.subContainer {
text-align: left;
}
.field {
font-size: 14px;
}
.input {
border-radius: 6px;
height: 25px;
margin-top: 10px;
border-color: silver;
border-style: solid;
background-color: cornsilk;
}
.tip {
margin-top: 5px;
font-size: 12px;
color: gray;
}
.setting {
font-size: 9px;
color: black;
}
.label {
font-size: 12px;
margin-left: 5px;
height: 20px;
vertical-align: middle;
}
.checkbox {
height: 20px;
vertical-align: middle;
}
.btn {
border-radius: 10px;
height: 40px;
width: 300px;
margin-top: 30px;
background-color: deepskyblue;
border-color: blue;
color: white;
}
</style>

11

实现注册页面的用户交互

获取用户输入的账号密码等,密码必须大于6位,邮箱校验

页面中3个文本输入框是通过循环动态渲染的,因此也需要采用动态的方式进行绑定

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="container" id="Application">
<div class="container">
<div class="subTitle">加入我们,一起创造美好世界</div>
<h1 class="title">创建你的账号</h1>
<div v-for="(item,index) in fields" class="inputContainer">
<div class="field">{{item.title}} <span v-if="item.required" style="color: red;">*</span></div>
<input v-model="item.model" class="input" :type="item.type">
<div class="tip" v-if="index == 2">请确认密码需要大于6位</div>
</div>

<div class="subContainer">
<div class="setting">偏好设置</div>
<input v-model="receiveMsg" class="checkbox" type="checkbox"><label class="label">接收更新邮件</label>
</div>
<button @click="createAccount" class="btn">创建账号</button>
</div>
</div>

Vue

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
80
<script>
const App={
data(){
return{
fields:[
{
title:'用户名',
required:true,
type:'text',
model:''
},
{
title:'邮箱地址',
required:true,
type:'text',
model:''
},
{
title:'密码',
required:true,
type:'password',
model:''
},
],
receiveMsg:false
}
},
computed:{
name:{
get(){
return this.fields[0].model
},
set(value){
this.fields[0].model=value
}
},
email:{
get(){
return this.fields[1].model
},
set(value){
this.fields[1].model=value
}
},
password:{
get(){
return this.fields[2].model
},
set(value){
this.fields[2].model=value
}
},
},
methods:{
emailCheck(){
var verify = /^\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/;
if (!verify.test(this.email)){
return false
}else{
return true
}
},
createAccount(){
if (this.name.length == 0){
alert("请输入用户名")
return
}else if (this.password.length <= 6){
alert("密码需要6位以上")
return
}else if (this.email.length > 0 && !this.emailCheck(this.email)){
alert("请输入正确的邮箱")
return
}
alert('注册成功')

}
}
}
Vue.createApp(App).mount("#Application")
</script>

通过配置输入框field对象来实现动态数据绑定,当用户单击创建账号按钮时,createAccount方法会进行一些有效性的校验。

22