浅谈vue组件
Updated:
一、组件化思想概念
- 组件化类似于在node中学习的模块化,模块化是一种思想,一种构建方式,把一种很复杂的事务拆分成一个一个小模块,然后通过某种特定的方式把这些 小模块组织到一起相互协作完成这个复杂的功能。
- 组件思想就是把一个很大的复杂的 Web 页面视图给拆分成一块一块的组件视图,然后利用某种特定的方式把它们组织到一起完成完整的 Web 应用构建。
在 Vue 中,组件就是用来封装视图的,说白了就是封装 HTML
- 为什么把视图给组件化拆成一块一块的呢?
- 开发效率
- 可维护性
- 其次才是可重用
二、Element
http://element-cn.eleme.io/#/zh-CN
- npm install element-ui –save
- 引入组件库css样式(lib/theme-chalk/index.css),再引入vue,其次是组件库js脚本
三、使用组件
- 先定义(注册)组件
- 使用
组件的模板 template
注意:只能有一个根元素,否则警告报错
3.1 template 可以是字面量字符串,缺点是没有高亮,内置在 JavaScript 中,写起来麻烦
3.2 template 可以写在 script 标签中,虽然解决了高亮的问题,但是也麻烦
3.3 以上方式都不好,我们最终的解决方案是使用 Vue 的 .vue 单文件组件来写。(webpack)但是要想使用这种方式必须结合一些构建工具
组件是独立的作用域,就像我们 Node 中的 JavaScript 模块一样,独立的
- 组件其实就是一个特殊的 Vue 实例,可以有自己的 data、methods、computed、watch 等等选项
- 组件的 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
30Vue.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. 组件分类
- 通用的组件,例如轮播图、评分
- 设计具体业务的组件,不通用
所以设计具体业务的尽量定义成局部,不要污染全局
3. 父—->子通信 [props Down]
- 在父组件中通过子组件标签声明属性的方式传递数据
**注意:只有 v-bind 才可以传递动态数据**
- 在子组件中声明 props 接收父组件传递给自己的数据
- 然后你就可以在子组件中对数据进行 “为所欲为”
只能使用,不要修改
例:
- 在父组件中将数据绑定传给子组件
1 | <todo-list |
- 在子组件中利用props接收
1
2
3
4
5
6
7template,
// 子组件就会把父组件在标签中声明的 foo 给拿过来
props: ['todos', 'filterText'],
data () {
return {
}
},
注意:在父组件传给子组件的数据中
- 在父组件中定义一个方法(纯业务方法)
- 在子组件内部调用父组件的方法
在子组件中发布一个自定义事件,通知父亲我可以去添加任务了- 在父组件使用子组件的标签上订阅子组件内部发布的自定义事件
例:
在父组件上定义好方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15methods: {
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
24methods: {
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>