Vue组件

组件化开发

组件化开发:根据封装的思想,把页面上可重用但是UI结构封装为组件,从而方便项目开发和维护。

vue中的组件化开发

vue是一个支持组件化开发的前端框架。

vue中规定:组件的后缀名是.vue,之前接触到的App.vue文件本质上是一个vue组件。

vue组件的三个组成部分

每个.vue组件都由3部分组成:

  • template: 组件的模板结构
  • script: 组件的JavaScript行为
  • style: 组件的样式

其中,每个组件必须包含template模板结构,而script行为和style样式是可选部分。

template

vue规定:每个组件对应的模板结构,需要定义到<template>节点中。

1
2
3
4
5
6
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>

注意,template只能包含唯一的根节点。

script

vue规定:开发者可以在<script>节点中封装组件的JavaScript业务逻辑。

1
2
3
4
5
6
7
8
9
10
11
<script>
import HelloWorld from './components/HelloWorld.vue'
// 今后,组件相关的data数据、methods等
// 都需要定义到 export default 所导出的对象中
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>

注意:.vue中的data必须是一个函数,不能直接指向一个数据对象。

style

vue规定:开发者可以在<style>节点中封装组件的样式风格。

1
2
3
4
5
6
7
8
9
10
<style lang="less">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

使用组件的三个步骤

  1. 使用import语法导入需要的组件。

    1
    2
    3
    <script>
    import Hello from './components/Hello.vue'
    </script>
  2. 使用components节点注册组件。

    1
    2
    3
    4
    5
    6
    7
    <script>
    import Hello from './components/Hello.vue'

    export default: {
    Hello
    }
    </script>
  3. 以标签形式使用刚才注册的组件。

    1
    2
    3
    4
    5
    <template>
    <div id="app">
    <Hello></Hello>
    </div>
    </template>

私有子组件和全局组件

私有子组件

通过components注册的是私有子组件。

例如:

在组件A的components节点下,注册了组件F。

则组件F只能用在组件A中,不能用在其它组件中。

全局组件

在vue项目中的main.js入口文件中,通过Vue.component()方法,可以注册全局组件。

1
2
3
4
5
6
// 导入需要全局注册的组件
import Count from '@/components/Count.vue'

// 参数1:字符串格式,表示组件的“注册名称”
// 参数2:需要被全局注册的那个组件
Vue.component('MyCount', Count)

组件的props

props是组件的自定义属性,在封装通用组件时,合理的使用props可以极大提高组件的复用性。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
<script>
export default {
//组件的自定义属性
props: ['自定义属性A', '自定义属性B', '其它自定义属性...'],

//组件的私有数据
data() {
return { }
}
}
</script>

props是只读的

vue规定组件中封装的自定义属性是只读的,程序与不能直接修改props的值,否则会报错。

想要修改props的值,可以将它转存到data中:

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
export default {
//组件的自定义属性
props: ['自定义属性A', '自定义属性B', '其它自定义属性...'],

//组件的私有数据
data() {
return {
count: this.init //把 this.init 的值转存到count
}
}
}
</script>

props的default默认值

在声明自定义属性时,可以通过default来定义属性的默认值。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
<script>
export default {
//组件的自定义属性
props: {
init: {
//用default属性定义属性的默认值
default: 0
}
}
}
</script>

props的type值类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
export default {
//组件的自定义属性
props: {
init: {
// 用default属性定义属性的默认值
default: 0
// 用type属性定义属性的值类型
// 如果传递归来的值不符合类型,则会在终端报错
type: Number
}
}
}
</script>

props的required必填项

在声明自定义属性的时候,可以通过required选项,将属性设置为必填项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
export default {
//组件的自定义属性
props: {
init: {
// 用default属性定义属性的默认值
default: 0
// 用type属性定义属性的值类型
// 如果传递归来的值不符合类型,则会在终端报错
type: Number
required: true
}
}
}
</script>

样式冲突问题

默认情况下,vue组件中的样式会全局生效。

原因:

  1. 单页面应用中,所有组件的DOM结构,都是基于唯一的index.html页面呈现的。
  2. 每个组件样式,都会影响整个index.html页面中的DOM元素。

解决方案:

为每个组件分配唯一的自定义属性,在编写组件样式时,通过属性选择器控制样式作用域。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div class="container" data-v-001>
<h3 data-v-001>轮播图组件</h3>
</div>
</template>

<style>
/* 通过中括号“属性选择器”,来防止组件之间的样式冲突问题
因为每个组件分配的自定义属性是唯一的 */
.container[data-v-001] {
border: 1px solid red;
}
</style>

style节点的scoped属性

为了提高效率,vue为style节点提供了scoped属性,从而防止组件样式冲突问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div class="container">
<h3>轮播图组件</h3>
</div>
</template>

<style scoped>
/* 自动为每个组件分配唯一的“自定义属性”
并自动为当前组件的DOM标签和style样式应用这个自定义属性,防止样式冲突问题 */
.container {
border: 1px solid red;
}
</style>

/deep/样式穿透

如果给当前组件的style节点添加了scoped属性,则当前组件的样式对其子组件不生效。

如果想让其样式对子组件生效,可以使用/deep/深度选择器。

代码示例:

1
2
3
4
5
<style lang="less" scoped>
/deep/ .title {
color: blue;
}
</style>