vue组件

什么是组件化开发

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

vue 中的组件化开发

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

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

vue 组件的三个组成部分

每个.vue 组件都由3 部分构成,分别是:

  1. template -> 组件的模板结构
  2. script-> 组件的JavaScript 行为
  3. style -> 组件的样式

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

三个完整部分组成的组件如下

注意:.vue 组件中的 data 不能指向对象,组件中的 data 必须是一个函数,在函数中 return 一个对象用来定义数据

在组件中 this 指向的是当前组件

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
<template>
<div class="d1">
<h3>这是我定义的test.vue模板结构 --- {{ username }}</h3>
<button @click="change">点击用户名会变</button>
</div>
</template>
<script>
// 默认导出
export default{
//data
// 注意.vue 组件中的data不能指向对象,
/* data:{
username:"heiheih"
} */
// 组件中的data 必须是一个函数
data(){
// return一个对象,用来定义数据
return {username:"yjr1100"}
},
methods:{
change(){
// 在vue 组件中this就表示当前组件的实例对象
this.username="yjr-1100"
}
},
// 当前组件的侦听器
watch:{},
// 当前组件中的计算属性
computd:{},
// 当前组件中的过滤器 注意这个只有vue2中有
filter:{}
}
</script>
<style>
.d1{
background-color: aquamarine;
}
</style>

注意: 组件必须要有唯一的根源素(即我们组件对外只能有一个div,其他的标签都应该被它包裹)

在组件中使用less

我们只需要在style 标签上添加 lang 属性,值为 less

1
2
3
<style lang="less">

</style>

组件的关系

当我们封装好几个组件后(一般App.vue放在src根目录中,其他组件放在components文件夹下),组件之间并没有关系,我们只是默认把 App.vue 渲染到了index.html 中,其他组件都没有使用,想要将组件都利用起来,我们必须合理使用组件,让他们之间形成嵌套关系,比如:父子关系或兄弟关系

组件使用的三个步骤

  1. App.vue 根组件中使用import语法导入其他组件

    1
    2
    3
    4
    // 1. 导入需要使用的 .vue 组件
    import Left from '@/components/Left.vue'
    import Test from "@/components/Test.vue"
    import Right from '@/components/Right.vue'
  2. components 节点中注册组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    export default {
    data() {
    return {
    flag: true
    }
    },
    // 2. 注册组件
    // 当建和值相同的时候,可以简写
    components: {
    Left,
    Right,
    Test
    }
    }
  3. 以标签形式使用组件

    1
    2
    <Left></Left>
    <Right></Right>

components节点

使用components节点注册的是私有组件,比如在 组件A 中注册了 组件F,那么组件F只能在组件A中使用,而在组件B中不能使用

注册全局组件

当某个节点需要频繁经常被使用的时候,如果我们每次都使用 components 来注册私有组件比较麻烦

我们通过 vue 项目的 main.js 入口文件中,使用 Vue.component() 方法,注册全局组件,注意不要在组件自己里面使用自己

1
2
3
4
5
// 导入需要被全局注册的那个组件
import Count from '@/components/Count.vue'
// 第一个参数是字符串组件的名字
// 第二个参数就是组件
Vue.component('MyCount', Count)

组件的props

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

在我们封装的组件中,添加 props 节点,该节点是一个数组/对象,可以自定义组件的属性

props 中的数据,可以直接在模板结构中被使用

注意:props 是只读的,不要直接修改 props 的值,否则终端会报错

使用的时候,我们需要在组件的标签中给自定义属性动态传入值<MyCount init="9"></MyCount>,直接在标签里这样写传给组件的是一个字符串9,所以我们利用 v-bind 绑定属性时写入的是js表达式这一特性,让 9 变为数字9.所以我们这样写 <MyCount :init="9"></MyCount>

当我们需要给自定义属性一个初始值时,props 就需要定义为对象,并在其中定义自定义属性,对于自定义属性我们可以定义它的配置选项, 比如 defaulttyperequired

数组形式的props 对象形式的props
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
export default {
// props 是"自定义属性",允许使用者通过自定义属性,为当前组件指定初始值
// 自定义属性的名字,是封装者自定义的(只要名称合法即可)
// props 中的数据,可以直接在模板结构中被使用
// 注意:props 是只读的,不要直接修改 props 的值,否则终端会报错!
props: ['init'],
data() {
return {
// 把 props 中的 init 值,转存到 count 上
count: this.init
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script>
export default {
props: {
// 自定义属性A : { /* 配置选项 */ },
// 自定义属性B : { /* 配置选项 */ },
// 自定义属性C : { /* 配置选项 */ },
init: {
// 如果外界使用 Count 组件的时候,没有传递 init 属性,则默认值生效
default: 0,
// init 的值类型必须是 Number 数字
type: Number,
// 必填项校验,代表使用组件时必须传入该属性
required: true
}
},
data() {
return {
// 把 props 中的 init 值,转存到 count 上
count: this.init
}
}
}
</script>
1
<MyCount :init="9"></MyCount>

组件的样式冲突

使用 scoped 属性

默认情况下,写在 .vue 组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。

导致组件之间样式冲突的根本原因是:

  1. 单页面应用程序中,所有组件的 DOM 结构,都是基于唯一的 index.html 页面进行呈现的

  2. 每个组件中的样式,都会影响整个 index.html 页面中的 DOM 元素

解决思路,使用属性选择器给当前组件里的标签都添加同一个自定义属性,每个不同的组件都使用不同的自定义属性,这样就会把样式限制在当前组件中了

事实上,如果让我们每次写标签的时候手动添加一个自定义属性会非常麻烦,只要我们在.vue 组件中的style 标签上添加一个 scoped 属性,在编译生成时,vue就会自动实现上面的功能,为我们的标签添加一个 data-v-xxxx 这样的自定义属性来避免组件之间的样式冲突

1
2
3
4
5
<style lang="less" scoped>
h3 {
color: red;
}
</style>

使用 /deep/ 样式穿透

当我们在父组件中想要修改子组件的样式时,如果我们的父组件添加了 scoped 属性,那么修改的样式并不能在子组件中生效,但如果我们不加 scoped 属性 那么样式又会在全局生效,影响布局,因此我们需要使用 /deep/ 来达到 在父组件中修改子组件样式的目的

1
2
3
4
5
6
7
8
9
<style lang="less" scoped>
// h5[data-v-3c83f0b7]
// [data-v-3c83f0b7] h5

// 当使用第三方组件库的时候,如果有修改第三方组件默认样式的需求,需要用到 /deep/
/deep/ h5 {
color: pink;
}
</style>

/deep/ 的原理是:在选择器前面添加一个属性选择器,代表该属性选择器包裹下的对应选择器使用该样式。当然添加的这个属性选择器,就是我们每个组件的自定义属性 data-v-xxx