前端组件化开发始于200X年,前端开发离不开HTML/CSS/JS,早期开发以页面为开发单位,三种语言各有特色,早期缺少固定规范,没有约束,野蛮开发。开发完时,前端开发者和上帝知道写的代码是什么意思;过了一个月后,就只有上帝知道这段代码什么意思。前端
随以前端组件这个概念逐渐在开发者脑海中生成,从早期的YUI、ExtJS再到web components,随着三大框架的出现,组件化开发开始家喻户晓,组件做为基本的抽象单元。React横空出世,让人们知道组件能够是函数,突破了人们原来基于页面的理解,经过将经常使用逻辑功能抽象成各类组件,方便开发时调用,测试,减小前端逻辑和ui的耦合等。vue
现阶段比较火的组件库,好比说antd系列以及elementui等,都是面向中后台系统开发出来的,由于中后台系统的功能相对来讲比较固定,UI样式要求并不复杂,能够在以往的业务逻辑中总结出一些经常使用的组件,将这些组件开发出来,方便中后台系统的开发。react
组件能够分为四类:web
这类组件能够是一个list或者是一个table,主要承担向用户展现服务端数据的功能。传入数据,组件渲染生成对应DOM。vue-router
例子:vue-router中配置挂载的vue组件,承担者和服务端获取、发送数据这样的功能,而后再一层一层传递给纯展现类组件。浏览器
例子:表单组件,时间日期选择组件等,包含比较复杂的用户交互逻辑,一种比较通用的逻辑,强调复用。markdown
抽象化的,提供某些抽象功能。vue-router中的router-view
和transation
组件。自己不渲染任何内容,做为一种扩展抽象机制的逻辑型组件存在antd
组件的两个基础就是props和event。框架
props:经过父组件传递props进来,简单组件能够将props转化成virtual DOM 最后再渲染成DOM,展示给用户。iview
event:组件须要支持除了浏览器原生事件以外,还须要支持一些组件的自定义事件,来支持UI交互功能。
slot:在如今三大框架下的组件,其实组件都是函数的概念,仅仅由props和event这样两个API只能开发一些简单的组件,开发复杂一些的组件还须要进一步的API支持,react中能够直接使用props去继承,而因为vue是SFC模式的,因此vue提供了slot这一API去弥补template
在这一场景下的不足。
综上,vue组件开发离不开的三大API就是props、event、slot。
这里给出iview做者的一个简易button的例子
<template>
<button
:class="'i-button-size' + size"
@click="handleClick"
:disabled="disabled"
>
<slot name="icon"></slot>
<slot></slot>
</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 {
inheritAttrs: false,
props: {
size: {
validator(value) {
return oneOf(value, ["small", "large", "default"]);
},
default: "default",
},
disabled: {
type: Boolean,
default: false,
},
},
created: function () {
console.log(this.$attrs); //注意这里
},
methods: {
handleClick(evt) {
this.$emit("click", evt);
},
},
};
</script>
复制代码
这里须要注意几点
1.开发组件须要指定props的类型,可能的话设定默认值,以及添加validator函数,进行参数校验,提高组件的稳定性。
2.经过inheritAttrs: false
和 $attrs
,咱们能够手动控制除了props以外的attribute具体怎么继承。须要注意的是inheritAttrs: false
并不能影响style
和class
的继承
不一样于组件和props,事件的命名大小写敏感,而且推荐使用kebab-case
的命名方式
以button组件中的点击事件为例子,有两种方式添加一个点击事件。
<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>
复制代码
直接在父级声明,但为了区分原生事件和自定义事件,要用到事件修饰符 .native
<i-button @click.native="handleClick"></i-button>
复制代码
这里再给出笔者写的一个简单版本的input组件
<template>
<div class="fr-input" :class="[inputSize?'fr-input--' + inputSize:'']">
<input
class="fr-input__inner"
:class="[inputSize?'fr-input__inner-'+inputSize:'']"
:readonly="readonly"
:value="value"
@input="handleInput"
@focus="handleFocus"
v-bind="$attrs"
autocomplete="off"
/>
</div>
</template>
<script>
export default {
name: 'FrInput',
props: {
value: [String, Number],
readonly: Boolean,
size: {
type: String
}
},
data() {
return {
focused: false
}
},
computed: {
inputSize() {
return this.size
}
},
methods: {
handleInput(event) {
this.$emit('input', event.target.value)
},
handleFocus(event) {
this.focused = true
this.$emit('focus', event)
}
}
}
</script>
复制代码
具体使用
<fr-input
v-model="phoneNumber"
type="text"
name="name"
spellcheck="false"
placeholder="请输入手机号"
class="input"
size="mform100"
></fr-input>
复制代码
这里须要注意:value="value"@input="handleInput"
其实就是v-model="value"
的语法糖,在vue2.2版本以上后,可使用model
选项来定制prop和event
在props中给出的button组件例子中,若是想在父组件中添加一些文字内容, 这里使用了slot的默认插槽还有slot="icon"
的具名插槽,插槽能够极大程度的扩展组件的功能。
<i-button>
<i-icon slot="icon" type="checkmark"></i-icon>
按钮 1
</i-button>
复制代码
本文简单介绍了一些组件化开发的概念、缘由以及vue组件化开发的相关API具体使用。接下来会进行一些更深刻的学习。