1. 组件化编程
1.1 组件
在 Vue 中,组件就是用来封装视图的,说白了就是封装 HTML;组件思想就是把一个很大的复杂的 Web 页面视图给拆分成一块一块的组件视图,然后利用某种特定的方式把它们组织到一起完成完整的 Web 应用构建
模块化是一种思想,一种构建方式,把一种很复杂的事务拆分成一个一个小模块,然后通过某种特定的方式把这些 小模块组织到一起相互协作完成这个复杂的功能
组件可以扩展HTML元素,封装可重用的代码。
在较高层面上,组件是自定义元素,Vue.js的编译器为它添加特殊功能。
在有些情况下,组件也可以变现为用 is 特性进行扩展原有的HTML元素
所有的Vue组件同时也都是Vue实例,所有可接受相同的选项的对象(除了一些根级特有的选项)并提供相同的生命周期钩子
1.2 组件的构成
组件主要包含三个部分:
- template模板:html结构,只可以定义一个父元素
- JS处理逻辑:主要作用是处理数据
- style处理样式:如果不加
scoped,默认就是全局样式
<!-- template模板 -->
<template>
<div class="title">
<h1>{{ msg }}</h1>
</div>
</template>
<!-- 逻辑处理 -->
<script>
export default {
props: []/{}, // props参数:可以是数组或者对象
// 自定义数据
data() {
return {
msg: 'hello vue.js'
};
},
computed: {}, //计算属性
methods: {}, //自定义方法
watch: {}, //监控
filters: {}, // 过滤器
directives: {}, // 自定义指令
components: {}, //自定义组件
};
</script>
<!-- 样式处理 -->
<style lang="scss" scoped></style>
1.3 组件的定义和使用
1.3.1 全局组件
定义组件
<template>
<div class="user">
<h1>这是一个全局组件</h1>
</div>
</template>
<script>
export default {}
</script>
<style lang="scss" scoped>
</style>
将组件注册为全局组件
一般是在main.js文件中 注册全局组件
// 1. 引入组件
import user from './components/user.vue'
// 2. 将组件注册为全局组件,名称为 my-user
Vue.component('my-user', user)
1.3.2 局部组件
定义组件
<template>
<div class="helloWorld">
<h1>这是一个局部组件</h1>
</div>
</template>
<script>
export default {}
</script>
<style lang="scss" scoped>
</style>
使用组件
<template>
<div class="test">
<!-- 3. 使用组件 -->
<user></user>
</div>
</template>
<script>
// 1. 引入组件
import user from './user.vue'
export default {
// 2. 注册声明组件
components: {
user,
},
}
</script>
<style lang="scss" scoped>
</style>
2 组件插槽
插槽可以实现 父组件与子组件之间的通信
如果子组件中的插槽的name和父组件不一致,那么通过父组件传递过去的 标签数据 就不会显示
2.1 插槽的定义
<slot name="slot-name"></slot>
2.2 插槽的使用
<div slot='slot-name'></div>
案例:
子组件
<template>
<div class="children">
<slot name="userNameSlot"></slot>
<div>子组件里面内容</div>
<slot name="contSlot"></slot>
</div>
</template>
父组件
<template>
<div id="app">
<children>
<h1 slot="userNameSlot">插槽 userNameSlot 显示的内容</h1>
<h1 slot="contSlot">插槽 contSlot 显示的内容</h1>
</children>
</div>
</template>
3 Prop
prop 是子组件用来接受父组件传递过来的数据的一个自定义属性
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop"
prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来
组件可以为 props 指定验证要求:
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
type 可以是下面原生构造器:
String Number Boolean Array Object Date Function Symbol
4 组件间的通信
组件间通信主要有5种方式:props、vue自定义事件、pubsub第三方库、slot插槽、vuex多组件共享状态
4.1 父组件向子组件通信
4.1.1 props
Prop是父组件用来传递数据的属性
父组件的数据需要通过props将数据传递给子组件,而子组件需要显式的用props声明prop
Prop是单向绑定的,当父组件的属性发生变化时,将传导给子组件,但是反过来不会
注意:不适合隔层组件和兄弟组件间的通信
1、 传递普通变量
2、 传递函数、方法
用法与传递普通变量一样
4.2 子组件向父组件通信
4.2.1 自定义事件--推荐
一般是 子组件 触发自定义事件,将参数传递给父组件
this.$emit('事件名',参数)
父组件绑定监听事件,接收子组件传递过来的参数
@事件名=回调函数
子组件:todoHeader触发事件
<script>
export default {
methods: {
add() {
const { title } = this
if (title.length > 0) {
var todoItem = { title, complete: false }
// 1. 使用 $emit('事件名',参数) 触发事件
this.$emit('addtodoItemSub', todoItem)
this.title = ''
} else {
alert('输入不可以为空!')
}
},
},
}
</script>
父组件:绑定监听事件
<template>
<div class="comtodolist">
<!-- 1. 给todoHeader绑定addtodoItemSub事件监听; addtodoItem1是一个回调函数-->
<todoHeader @addtodoItemSub="addtodoItem1"></todoHeader>
</div>
</template>
<script>
import todoHeader from '../components/component-todolist/todoHeader.vue'
export default {
methods: {
// 2. 添加 todoItem 父组件定义的回调函数
addtodoItem1(todoItem) {
this.todos.unshift(todoItem)
},
},
}
</script>
4.2.2 ref 结合 $on
使用$on(事件名,回调函数) 绑定监听
子组件todoHeader:触发事件
<script>
export default {
methods: {
add() {
const { title } = this
if (title.length > 0) {
var todoItem = { title, complete: false }
// 1. 使用 $emit('事件名',参数) 触发事件
this.$emit('addtodoItemSub', todoItem)
this.title = ''
} else {
alert('输入不可以为空!')
}
},
},
}
</script>
父组件:绑定监听事件 $on
<template>
<div class="comtodolist">
<!-- 1. 给子组件设置 ref -->
<todoHeader ref="todoheaderref"></todoHeader>
</div>
</template>
<script>
import todoHeader from '../components/component-todolist/todoHeader.vue'
export default {
name: 'todolist',
data() {
return {
// 从slocalStorage中读取todos
todos: JSON.parse(window.localStorage.getItem('todos_key') || '[]'),
}
},
components: {
todoHeader,
},
mounted() {
// 2. 绑定监听事件 this.$on('addtodoItemSub', this.addtodoItem);
this.$refs.todoheaderref.$on('addtodoItemSub', this.addtodoItem)
},
methods: {
// 添加
addtodoItem(todoItem) {
this.todos.unshift(todoItem)
},
},
}
</script>
4.3 pubsub:消息订阅与发布
可以实现任意组件之间的通信:父子组件传值或同胞兄弟之间的传值
# 安装
npm i pubsub-js
# 判断是否安装成功
npm info pubsub-js
4.3.1 订阅消息(绑定事件监听): 定义函数或方法
// 语法
PubSub.subscribe('方法名',(msg,data)=>{} )
或者是下面的这种
PubSub.subscribe('事件名',function(msg,data){}) data就是参数
// 案例展示:订阅消息 searchInfo
// 注意:此处必须使用 箭头函数,才可以获取 this.searchInfo方法
PubSub.subscribe('searchInfo', (msg, searchName) => {
this.searchInfo(searchName);
});
methods:{
searchInfo(searchName){
console.log(searchName);
}
}
4.3.2 发布消息(触发事件):调用函数或方法
// 语法
PubSub.publish('方法名',data)
// 案例展示:发布消息 searchInfo
import PubSub from 'pubsub-js';
//发布消息:触发事件 searchNameText参数名
PubSub.publish('searchInfo', searchNameText);
4.5 slot插槽
主要是父组件向子组件传递带数据的标签数据
注意: 标签是在父组件中解析
// slot插槽定义
<slot name="slotName">不确定的标签结构 1</slot>
// slot插槽使用
<div slot="slotName">slotName 对应的标签结构</div>
案例展示:
子组件 Child.vue
<template>
<div>
<slot name="xxx">不确定的标签结构 1</slot>
<div>组件确定的标签结构</div>
<slot name="yyy">不确定的标签结构 2</slot>
</div>
</template>
父组件
<child>
<div slot="xxx">xxx 对应的标签结构</div>
<div slot="yyy">yyyy 对应的标签结构</div>
</child>
4.6 vuex
多组件共享状态(数据的管理
组件间的关系也没有限制
功能比pubsub强大, 更适用于vue项目