在进入vue开发的过程中,我们上一节已经探讨了vue入门中的进本语法,标签绑定等。这一节我们具体结合一个案例来理解vue中的组件开发
1,工程结构分析
我们将要创建一个如下图的简单工程

我们将这个模块拆分为如下小块

所以我们在components目录中创建了如下的模块

2,创建模板工程
在选定的工程目录中使用如下命令,进行模板的创建;
vue init webpack vue-demo
关于eslint,test等模块单元,我们暂时先不考虑,直接选择no
cd vue-demo 进入工程目录,进行其他组件的安装 npm install
模板测试:npm run dev
进入浏览器 输入localhost:8080,出现vue logo界面即认为模板创建成功
模板结构如下:

3, 创建项目基本结构

- 1, 在app.vue标签中引入我们创建好的组件标签
<template>
<div class="todo-container">
<div class="todo-wrap">
<!-- 1,先引入三个组件,具体实现待各个组件自己完成-->
<!-- <TodoHeader :addTodo="addTodo"/> -->
<TodoHeader ref="header"/>
<TodoList :todos = "todos"/>
<TodoFooter/>
</div>
</div>
</template>
- 2, 在app.vue中引入组件
// 2,引入的组件需要被导入才可以被使用
import PubSub from 'pubsub-js'
import TodoHeader from './components/TodoHeader'
import TodoList from './components/TodoList'
import TodoFooter from './components/TodoFooter'
import storageUtils from './utils/storageUtils'
- 3, 声明引入的组件,这样我们就可以使用这些组件
// 3, 引入组件之后,需要声明这些组件,模板中才可以使用
components: {
TodoHeader,
TodoList,
TodoFooter
}
- 在各个组件引入各个组件各自的css样式(不展示)
现在我们启动运行 npm run dev 就可以看到我们要做的项目的基本静态页面了

现在我们需要考虑一个问题,就是组件之间如何通信呢,也就是app.vue如何与他们的子组件如何进行互动呢?
4, vue组件间进行通信
vue组件之间的通信有如下5种方式,今天我们会在这里讲述前4中
1) props
2) vue 的自定义事件
3) 消息订阅与发布(如: pubsub 库)
4) slot
5) vuex(后面单独讲)
-
4.1 props 通信
- 在app.vue中的TodoList组件中使用如下强制绑定的方式,将数据传递到TodoList组件中
<TodoList :todos = "todos"/>- 当然,这个todos是需要在app.vue中定义的数据
data () { return { todos: storageUtils.readTodos() // 从浏览器缓存中获取数据 storageUtils后面再讲 } },- 在TodoList组件中接收父组件app.vue中传递过来的数据
<template> <ul class="todo-main"> <TodoItem v-for="(todo,index) in todos" :key="index" :todo="todo" :index="index"/> <!-- todos为app.vue中传递过来的,:todo是要传递到下一个组件的数据,index也是如此--> </ul> </template>import TodoItem from './TodoItem' export default { // 3, 传递过来的数据要进行显示声明. 声明接收标签属性 props:[ 'todos','deleteTodo' // 这样的声明可以接收数据,也可以接收方法等之类的数据 ], components: { TodoItem } }这样我们就通过props的方式将数据从父组件传递到了子组件。
说明:props只能向子组件传递数据,不能是子组件向父组件传递数据。
-
4.2 绑定事件监听 进行组件通信
在app.vue中header组件标定一个唯一事件标记
<TodoHeader ref="header"/>
在app.vue中向这个组件注册函数
mounted(){
this.$refs.header.$on('addTodo', this.addTodo)
},
methods: {
addTodo (todo) {
this.todos.unshift(todo)
}
}
在TodoHeader组件中使用这个声明的函数
methods: {
add () {
...
/*触发自定义事件: addTodo*/
this.$emit('addTodo', todo) // 需要使用$emit函数才能调用
// 清除输入
this.inputTodo = ''
}
}
注意:此方式只用于子组件向父组件发送消息(数据)
问题: 隔代组件或兄弟组件间通信此种方式不合适
- 4.3 组件间通信,消息订阅与发布(PubSubJS 库)
使用此组件需要安装
安装完毕我们就可以使用该组件了
在app.vue中对外订阅一个函数
mounted(){
// 订阅消息(deleteTodo) // 会随时监听这个函数是否有发布新的消息
PubSub.subscribe('deleteTodo', (msg, index) => {
this.deleteTodo(index)
})
}
定义一个删除的函数
methods: {
deleteTodo (index) {
this.todos.splice(index, 1)
}
}
在ListItem组件中发布一个删除方法
methods: {
deleteItem () {
// 发布消息(deleteTodo)
PubSub.publish('deleteTodo', this.index)
}
优点: 此方式可实现任意关系组件间通信(数据)
- 4.4 组件间通信 slot
在app.vue中引入的footer.vue组件中添加slot组件
<TodoFooter>
<input type="checkbox" v-model="checkAll" slot="checkAll"/>
<span slot="size">已完成 / 全部</span>
<button class="btn btn-danger" v-show="completeSize" @click="deleteAllCompleted" slot="delete">清除已完成任务</button>
</TodoFooter>
slot中可以引入方法,或者我们绑定的数据
在footer.vue中使用这些定义的slot组件
<template>
<div class="todo-footer">
<label>
<slot name="checkAll"></slot>
</label>
<span>
<slot name="size"></slot>
</span>
<slot name="delete"></slot>
</div>
</template>
此方式用于父组件向子组件传递标签数据
这样我们整个的vue组件间通信就介绍完毕了。