Contents
  1. 1. 一、组件化思想概念
  2. 2. 二、Element
  3. 3. 三、使用组件
  4. 4. 四、组件通信
    1. 4.0.1. 1. 全局组件和局部组件
    2. 4.0.2. 2. 组件分类
    3. 4.0.3. 3. 父—->子通信 [props Down]
    4. 4.0.4. 4. 子—-> 父传值 [Events Up]

一、组件化思想概念

  • 组件化类似于在node中学习的模块化,模块化是一种思想,一种构建方式,把一种很复杂的事务拆分成一个一个小模块,然后通过某种特定的方式把这些 小模块组织到一起相互协作完成这个复杂的功能。
  • 组件思想就是把一个很大的复杂的 Web 页面视图给拆分成一块一块的组件视图,然后利用某种特定的方式把它们组织到一起完成完整的 Web 应用构建。

在 Vue 中,组件就是用来封装视图的,说白了就是封装 HTML

  • 为什么把视图给组件化拆成一块一块的呢?
    • 开发效率
    • 可维护性
    • 其次才是可重用

二、Element

http://element-cn.eleme.io/#/zh-CN

  1. npm install element-ui –save
  2. 引入组件库css样式(lib/theme-chalk/index.css),再引入vue,其次是组件库js脚本

三、使用组件

  1. 先定义(注册)组件
  2. 使用
  3. 组件的模板 template
    注意:只能有一个根元素,否则警告报错
    3.1 template 可以是字面量字符串,缺点是没有高亮,内置在 JavaScript 中,写起来麻烦
    3.2 template 可以写在 script 标签中,虽然解决了高亮的问题,但是也麻烦
    3.3 以上方式都不好,我们最终的解决方案是使用 Vue 的 .vue 单文件组件来写。(webpack)

    但是要想使用这种方式必须结合一些构建工具
    
  4. 组件是独立的作用域,就像我们 Node 中的 JavaScript 模块一样,独立的

    1. 组件其实就是一个特殊的 Vue 实例,可以有自己的 data、methods、computed、watch 等等选项
  5. 组件的 data 必须是函数
    函数中返回一个对象作为组件的 data

例:感知基本组件:

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
Vue.component('my-component', {
template: `
<div>
<div>My Component</div>
<h2>{{ message }}</h2>
<input type="text" v-model="message" />
<button @click="handleClick">点击弹出自己的 message</button>
<input type="checkbox" v-model="checked" />
<div class="box" v-if="checked"></div>
</div>
`,
data () {
return {
message: 'Component Data',
checked: true
}
},
methods: {
handleClick () {
window.alert(this.message)
}
}
})

const app = new Vue({
data: {
message: 'Hello Vue.js!'
},
methods: {}
}).$mount('#app')

例:单文件组件(.vue文件)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- 
但是这种方式浏览器不能直接识别,需要结合 webpack 构建工具才能玩儿。
-->

<!-- 组件的模板,写到 template 中 -->
<template>
<div></div>
</template>

<!-- 组件的 JavaScript 脚本写到 script 标签中 -->
<script>
export default {
data () {
return {}
}
}
</script>

<!-- 组件的 CSS 写到 style 标签中 -->
<style>
</style>

四、组件通信

1. 全局组件和局部组件

  • Vue.component生成的组件是全局的组件
  • 在上面这个vue实例中使用components配置的组件是局部的组件
    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
    <body>
    <div id="app">
    <h1>{{ message }}</h1>
    <hello></hello>
    <global-component></global-component>
    </div>
    <script src="node_modules/vue/dist/vue.js"></script>
    <script>
    Vue.component('global-component', {
    template: `<div>
    <h2>global component</h2>
    <global2-component></global2-component>
    <hello></hello>
    </div>`,
    // 组件实例选项 components 也是用来定义组件,但是这种方式定义的组件只能在当前组件中使用
    components: {
    // 键名就是组件名称,值是一个对象,对象中配置组件的选项
    hello: {
    template: '<div>hello component</div>'
    }
    }
    })

    Vue.component('global2-component', {
    template: '<div>global2 component</div>'
    })

    Vue.component('global2-component', {
    template: '<div>global3 component</div>'
    })

    const app = new Vue({
    data: {
    message: 'Hello Vue.js!'
    },
    methods: {}
    }).$mount('#app')
    </script>
    </body>

结果如下图所示
结果
可以看出在app中hello报错,因为hello不是全局组件

2. 组件分类

  1. 通用的组件,例如轮播图、评分
  2. 设计具体业务的组件,不通用

所以设计具体业务的尽量定义成局部,不要污染全局

3. 父—->子通信 [props Down]

  1. 在父组件中通过子组件标签声明属性的方式传递数据
    **注意:只有 v-bind 才可以传递动态数据**
    
  2. 在子组件中声明 props 接收父组件传递给自己的数据
  3. 然后你就可以在子组件中对数据进行 “为所欲为”
    只能使用,不要修改
    

例:

  1. 在父组件中将数据绑定传给子组件
1
2
3
<todo-list
:todos="todos"
:filterText="filterText"></todo-list>
  1. 在子组件中利用props接收
    1
    2
    3
    4
    5
    6
    7
    template,
    // 子组件就会把父组件在标签中声明的 foo 给拿过来
    props: ['todos', 'filterText'],
    data () {
    return {
    }
    },

注意:在父组件传给子组件的数据中

  • 引用类型的数据可以修改,但不能重新赋值(不建议,会违背通信原则即单向数据流原则)
  • 普通类型不允许修改(子组件无修改父组件的能力)

    4. 子—-> 父传值 [Events Up]

  1. 在父组件中定义一个方法(纯业务方法)
  2. 在子组件内部调用父组件的方法
    在子组件中发布一个自定义事件,通知父亲我可以去添加任务了
    1. 在父组件使用子组件的标签上订阅子组件内部发布的自定义事件

例:
在父组件上定义好方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
methods: {
addTodo (titleText) {
console.log('父组件的 addTodo 方法被调用了')
titleText = titleText.trim()
if (!titleText.length) {
return
}
const todos = this.todos
todos.push({
id: todos[todos.length - 1].id + 1,
title: titleText,
completed: false
})
}
}

在子组件内部调用其方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
methods: {
handleKeydown (e) {
// 0. 获取文本框的值
// 1. 非空校验
// 2. 添加任务到 todos 中
const target = e.target
const value = target.value.trim()
if (!value.length) {
return
}

// 在子组件中数据已经准备就绪,可以交给父组件使用了
// 子组件通知父组件你去 addTodo 去吧。
// 子组件不关心父组员的业务
// 父组件到底拿到这个数据干嘛?
// 对于子组件来讲,根本不关心,你爱干嘛干嘛
// 由于不关心业务,所以该组件重用的几率将会大大的增加
// 谁来用我,我就就把数据给谁
this.$emit('addTodo', value)

target.value = ''

}
}

在父组件使用子组件的标签上订阅子组件内部发布的自定义事件

1
2
3
4
<todo-header
:todos="todos"
:foo="foo"
@addTodo="addTodo"></todo-header>

Contents
  1. 1. 一、组件化思想概念
  2. 2. 二、Element
  3. 3. 三、使用组件
  4. 4. 四、组件通信
    1. 4.0.1. 1. 全局组件和局部组件
    2. 4.0.2. 2. 组件分类
    3. 4.0.3. 3. 父—->子通信 [props Down]
    4. 4.0.4. 4. 子—-> 父传值 [Events Up]