Vue.js 组件的三个 API:prop、event、slot
组件的构成
一个再复杂的组件,都是由三部分组成的:prop、event、slot,它们构成了 Vue.js 组件的 API。如果你开发的是一个通用组件,那一定要事先设计好这三部分,因为组件一旦发布,后面再修改 API 就很困难了,使用者都是希望不断新增功能,修复 bug,而不是经常变更接口。如果你阅读别人写的组件,也可以从这三个部分展开,它们可以帮助你快速了解一个组件的所有功能。
属性 prop
prop 定义了这个组件有哪些可配置的属性,组件的核心功能也都是它来确定的。写通用组件时,props 最好用对象的写法,这样可以针对每个属性设置类型、默认值或自定义校验属性的值,这点在组件开发中很重要,然而很多人却忽视,直接使用 props 的数组用法,这样的组件往往是不严谨的。比如我们封装一个按钮组件 <i-button>:
<template>
<button :class="'i-button-size' + size" :disabled="disabled"></button>
</template>
<script>
// 判断参数是否是其中之一
function oneOf (value, validList) {
for (let i = 0; i < validList.length; i++) {
if (value === validList[i]) {
return true;
}
}
return false;
} export default {
props: {
size: {
validator (value) {
return oneOf(value, ['small', 'large', 'default']);
},
default: 'default'
},
disabled: {
type: Boolean,
default: false
}
}
}
</script>
使用组件:
<i-button size="large"></i-button>
<i-button disabled></i-button>
组件中定义了两个属性:尺寸 size 和 是否禁用 disabled。其中 size 使用 validator 进行了值的自定义验证,也就是说,从父级传入的 size,它的值必须是指定的 small、large、default 中的一个,默认值是 default,如果传入这三个以外的值,都会抛出一条警告。
要注意的是,组件里定义的 props,都是单向数据流,也就是只能通过父级修改,组件自己不能修改 props 的值,只能修改定义在 data 里的数据,非要修改,也是通过后面介绍的自定义事件通知父级,由父级来修改。
在使用组件时,也可以传入一些标准的 html 特性,比如 id、class:
<i-button id="btn1" class="btn-submit"></i-button>
这样的 html 特性,在组件内的 <button> 元素上会继承,并不需要在 props 里再定义一遍。这个特性是默认支持的,如果不期望开启,在组件选项里配置 inheritAttrs: false 就可以禁用了。
插槽 slot
如果要给上面的按钮组件 <i-button> 添加一些文字内容,就要用到组件的第二个 API:插槽 slot,它可以分发组件的内容,比如在上面的按钮组件中定义一个插槽:
<template>
<button :class="'i-button-size' + size" :disabled="disabled">
<slot></slot>
</button>
</template>
这里的 <slot> 节点就是指定的一个插槽的位置,这样在组件内部就可以扩展内容了:
<i-button>按钮 1</i-button>
<i-button>
<strong>按钮 2</strong>
</i-button>
当需要多个插槽时,会用到具名 slot,比如上面的组件我们再增加一个 slot,用于设置另一个图标组件:
<template>
<button :class="'i-button-size' + size" :disabled="disabled">
<slot name="icon"></slot>
<slot></slot>
</button>
</template>
<i-button>
<i-icon slot="icon" type="checkmark"></i-icon>
按钮 1
</i-button>
这样,父级内定义的内容,就会出现在组件对应的 slot 里,没有写名字的,就是默认的 slot。
在组件的 <slot> 里也可以写一些默认的内容,这样在父级没有写任何 slot 时,它们就会出现,比如:
<slot>提交</slot>
自定义事件 event
现在我们给组件 <i-button> 加一个点击事件,目前有两种写法,我们先看自定义事件 event(部分代码省略):
<template>
<button @click="handleClick">
<slot></slot>
</button>
</template>
<script>
export default {
methods: {
handleClick (event) {
this.$emit('on-click', event);
}
}
}
</script>
通过 $emit,就可以触发自定义的事件 on-click ,在父级通过 @on-click 来监听:
<i-button @on-click="handleClick"></i-button>
上面的 click 事件,是在组件内部的 <button> 元素上声明的,这里还有另一种方法,直接在父级声明,但为了区分原生事件和自定义事件,要用到事件修饰符 .native,所以上面的示例也可以这样写:
<i-button @click.native="handleClick"></i-button>
如果不写 .native 修饰符,那上面的 @click 就是自定义事件 click,而非原生事件 click,但我们在组件内只触发了 on-click 事件,而不是 click,所以直接写 @click 会监听不到。
组件的通信
一般来说,组件可以有以下几种关系:

A 和 B、B 和 C、B 和 D 都是父子关系,C 和 D 是兄弟关系,A 和 C 是隔代关系(可能隔多代)。组件间经常会通信,Vue.js 内置的通信手段一般有两种:
ref:给元素或组件注册引用信息;$parent/$children:访问父 / 子实例。
这两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据,比如下面的示例中,用 ref 来访问组件(部分代码省略):
// component-a
export default {
data () {
return {
title: 'Vue.js'
}
},
methods: {
sayHello () {
window.alert('Hello');
}
}
}
<template>
<component-a ref="comA"></component-a>
</template>
<script>
export default {
mounted () {
const comA = this.$refs.comA;
console.log(comA.title); // Vue.js
comA.sayHello(); // 弹窗
}
}
</script>
$parent 和 $children 类似,也是基于当前上下文访问父组件或全部子组件的。
这两种方法的弊端是,无法在跨级或兄弟间通信,比如下面的结构:
// parent.vue
<component-a></component-a>
<component-b></component-b>
<component-b></component-b>
我们想在 component-a 中,访问到引用它的页面中(这里就是 parent.vue)的两个 component-b 组件,那这种情况下,就得配置额外的插件或工具了,比如 Vuex 和 Bus 的解决方案
基于 Vue.js 开发独立组件,并不是新奇的挑战,坦率地讲,它本质上还是 JavaScript。掌握了 Vue.js 组件的这三个 API 后,剩下的便是程序的设计。在组件开发中,最难的环节应当是解耦组件的交互逻辑,尽量把复杂的逻辑分发到不同的子组件中,然后彼此建立联系,在这其中,计算属性(computed)和混合(mixins)是两个重要的技术点,合理利用,就能发挥出 Vue.js 语言的最大特点:把状态(数据)的维护交给 Vue.js 处理,我们只专注在交互上。
来源:https://mp.weixin.qq.com/s/BWdGWFNVpdgG1tVQ0Lm9XA
Vue.js 组件的三个 API:prop、event、slot的更多相关文章
- vue.js组件化开发实践
前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎么实现,技术选型自然 ...
- VUE.JS组件化
VUE.JS组件化 前言 公司目前制作一个H5活动,特别是有一定统一结构的活动,都要码一个重复的轮子.后来接到一个基于模板的活动设计系统的需求,便有了下面的内容.借油开车. 组件化 需求一到,接就是怎 ...
- Vue.js 组件编码规范
本规范提供了一种统一的编码规范来编写 Vue.js 代码.这使得代码具有如下的特性: 其它开发者或是团队成员更容易阅读和理解. IDEs 更容易理解代码,从而提供高亮.格式化等辅助功能 更容易使用现有 ...
- 如何理解vue.js组件的作用域是独立的
vue.js组件的作用域是独立,可以从以下三个方面理解: 1.父组件模板在父组件作用域内编译,父组件模板的数据用父组件内data数据:2.子组件模板在子组件作用域内编译,子组件模板的数据用子组件内da ...
- 浅尝Vue.js组件(一)
本篇目录: 组件名 组件注册 全局注册 基础组件的自动化全局注册 局部注册 在模块系统中局部注册 Prop 单向数据流 Prop验证 类型检查 非Prop特性 替换/合并已有的特性 禁用特性继承 自定 ...
- Vue.js组件的重要选项
Vue.js组件的重要选项 实例化Vue对象一些很重要的选项,Vue的所有数据都是放在data里面的,Vue的参数是个对象,对象里面的字段叫做data,data里面也是对象,data也可以写作是thi ...
- vue.js组件之j间的通讯三,通过单一事件来管理组件通讯
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- vue.js组件(component)
简介: 组件(Component)是 Vue.js 最强大的功能之一. 组件可以扩展 HTML 元素,封装可重用的代码. 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面 ...
- Vue.js 组件复用和扩展之道
软件编程有一个重要的原则是 D.R.Y(Don't Repeat Yourself),讲的是尽量复用代码和逻辑,减少重复.组件扩展可以避免重复代码,更易于快速开发和维护.那么,扩展 Vue 组件的最佳 ...
随机推荐
- Django 跨域CORS
现在,前端与后端分处不同的域名,我们需要为后端添加跨域访问的支持. 我们使用CORS来解决后端对跨域访问的支持. 使用django-cors-headers扩展 参考文档https://github. ...
- Python_练习_VS清理器
#导入os import os #创建列表放入后缀 d=[ '.txt','obj','tlog','lastbuildstate','idb','pdb','pch','res','ilk','sd ...
- Bzoj 3307 雨天的尾巴(线段树合并+树上差分)
C. 雨天的尾巴 题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入格式 第 ...
- Linux下MySQL 5.7的初始化
要用管理员账号运行. systemctl start mysql#启动MySQL服务 mysqld_safe --user=mysql &#启动MySQL服务(安全方式) mysql -u r ...
- SQL函数解释(待补)
1.SQL— CONCAT(字符串连接函数) 有的时候,我们有需要将由不同栏位获得的资料串连在一起.每一种资料库都有提供方法来达到这个目的: MySQL: CONCAT() Oracle: CONCA ...
- JFinal项目eclipse出现the table mapping of model: com.gexin.model.scenic.Scenic not exists or the ActiveRecordPlugin not start.
JFinal项目eclipse出现the table mapping of model: com.gexin.model.scenic.Scenic not exists or the ActiveR ...
- 获取url上的参数
var aa = '?name=hss&age=13'; function strToObj(str){ if(typeof str === 'undefi ...
- 牛客网 nowcoder TG test-172
# solution-nowcoder-172 # A-中位数 $30\%:n\le 200$ 直接枚举 $n-len+1$ 个区间,将这段里的数重新排序直接找到中位数 $60\%:n\le 2000 ...
- 笔试算法题(07):还原后序遍历数组 & 半翻转英文句段
出题:输入一个整数数组,判断该数组是否符合一个二元查找树的后序遍历(给定整数数组,判定其是否满足某二元查找树的后序遍历): 分析:利用后序遍历对应到二元查找树的性质(序列最后一个元素必定是根节点,从左 ...
- <Redis> 入门三 事务
Redis事务是什么 1.可以一次执行多个命令,本质是一组命令的集合. 2.一个事务中的所有命令都会被序列化,按顺序串行化执行而不会被其他命令插入,不许加塞. 意味着redis在事务执行的过程中,不允 ...