组件

定义与使用 vue 组件

组件就是应用里面一块可以重复使用的界面。
定义一个组件:

1
2
3
<template>
<button>按钮</button>
</template>

在其他地方使用的时候,需要先在 script 中引入并声明

1
2
3
4
5
6
7
8
import AppButton from './components/app-button';
export default {
data() {
},
components: {
AppButton,
},
};

然后在 template 中就可以使用了,以下几种写法都可。

1
2
3
4
5
6
7
<template>
<AppButton></AppButton> //可以写结束标签
<AppButton /> //也可以写成自关闭

<app-button></app-button> //还可以写成串串
<app-button />
</template>

vue 组件的样式
组件的样式可以直接写在 style 标签里,也可以写在样式表里,在 style 中用@import 的方式引入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<style>
.button {
outline: none;
border: none;
background: #e1e1e1;
color: #5a5a5a;
padding: 8px 16px;
margin: 4px;
cursor: pointer;
border-radius: 3px;
}
.button:active {
opacity: 0.8;
}
</style>

scoped 限定组件样式的应用范围
默认情况下,组件间的样式会相互影响。如果想限定样式只在当前组件内有效的话,可以在组件的 style 标签上添加 scoped,这样组件的样式就私有化了。加了这个东西以后,会在这个组件的模板元素上面添加一个特定的 data 属性。


props vue 组件的属性
父组件可以通过 props 把数据传递给子组件。

组件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<button class="button">{{ text }}</button>
</template>

<script>
export default {
props: {
text: {
type: String,
default: '按钮',
},
},
};
</script>

使用的时候:

1
2
3
4
5
6
7
8
<template>
<h3>{{ name }}</h3>
<AppButton text="确定"></AppButton>
<AppButton />

<app-button></app-button>
<app-button />
</template>

监听子组件的事件
在一个组件里使用了另一个组件,他们之间就有了父子关系。子组件发生的事情可以通过自定义的事件告诉给父组件。
子组件:

1
<button class="button" @click="$emit('tap', text)">{{ text }}</button>

父组件:

1
2
3
4
<AppButton
text="确定"
@tap="onTapAppButton"
></AppButton>
1
2
3
4
5
methods: {
onTapAppButton(text) {
console.log('on tap app button', text);
}
}

slot 在 vue 组件里用插槽分发内容
在定义组件的时候可以添加一些 slot,这样在使用组件的时候,可以设置插槽的内容。
子组件:

1
2
3
<button class="button" @click="$emit('tap', text)">
<slot></slot>
</button>

父组件:

1
<AppButton @tap="onTapAppButton" @init="onInitAppButton">提交</AppButton>

动态组件
在页面中如果你想切换使用不同的组件,可以使用动态组件功能。
举个栗子:新建三个子组件,user-login.vue 用户登录,user-register.vue 用户注册,user-profile.vue 界面

user-login.vue:

1
2
3
4
5
<template>
<div>用户登录</div>
<input type="text" />
<input type="text" />
</template>

user-register.vue:

1
2
3
4
5
<template>
<div>注册用户</div>
<input type="text" />
<input type="text" />
</template>

user-profile.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
<template>
<component :is="currentComponent"></component>
<small @click="onClickHintText">{{ hintText }}</small>
</template>

<script>
import UserLogin from './user-login';
import UserRegister from './user-register';
export default {
data() {
return {
currentComponent: 'UserLogin', //要显示的子组件
hintText: '还没有账户,点击注册', //提示信息
};
},
methods: {
onClickHintText() {
switch (this.currentComponent) {
case 'UserRegister':
this.currentComponent = 'UserLogin';
this.hintText = '还没有账户,点击注册';
break;
case 'UserLogin':
this.currentComponent = 'UserRegister';
this.hintText = '已有账户,点击登录';
break;
}
},
},
components: {
UserRegister,
UserLogin,
},
};
</script>

父组件中使用:

1
<UserProfile></UserProfile>
1
2
3
4
import UserProfile from './components/user-profile';
components: {
UserProfile,
},

这样在页面中点击的时候就可以在登录和注册之间切换了。


keep-alive 保持动态组件的活动状态
比如上面动态组件的栗子,在一个组件里填写后切换到另一个组件,再切换回来,你会发现刚才填写的东西不见了。如果你想保存组件的状态,可以使用 keep-alive。

1
2
3
<keep-alive>
<component :is="currentComponent"></component>
</keep-alive>

$refs 引用模板
有时候我们希望可以直接访问到子组件,或者某一个具体的 html 元素,这时候我们可以在子组件或者 html 元素上使用 ref,去分配一个引用的 id,然后在代码里使用这个引用的 id 就可以访问到这个组件或者 html 元素。比如我希望在组件挂在后,让文本框自动进入焦点状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div>用户登录</div>
<input type="text" ref="username" />
<input type="text" />
</template>

<script>
export default {
mounted() {
console.log(this.$refs.username);
this.$refs.username.focus();
},
};
</script>

在自定义组件上使用 v-model
在自定义组件上使用 v-model 需要额外处理一下。
子组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<input
type="text"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>

<script>
export default {
props: {
modelValue: String,
},
};
</script>

父组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div>用户登录 {{ username }}</div>
<AppInput v-model="username" />
</template>

<script>
import AppInput from './app.input';
export default {
data() {
return {
username: '',
};
},
components: {
AppInput,
},
};
</script>

组件的生命周期方法
beforeCreate:组件创建前
beforeMount:组件挂载前
beforeUpdate:组件更新前
created:组件创建后
mounted:组件挂载后
updated:组件更新后
unmounted:组件卸载后