开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
前言
说到组件开发,最简单、最基本的就得是button组件开发了。本文将逐步实现z-button和z-editor组件。
组件实现
z-button组件
纵观任一一种组件库,button组件所提供的功能不外乎是按钮文字,按钮样式,以及按钮事件这三个方面。
要实现按钮文字,也就是使用组件的插槽功能即可实现
<template>
<button class="z-default">
<slot/>
</button>
</template>
要实现按钮样式的绑定,首先得确定好按钮的基础样式,以及每种状态下对应的样式。从而使用:style=""
来绑定。当父组件传入primary、success、danger、warning
的时候,z-button组件应在内部转换一下在绑定到样式里。
基本的css
.z-default{
……
}
.z-primary{
background-color: blue;
}
.z-success{
background-color: green;
}
.z-warning{
background-color: yellow;
}
.z-danger{
background-color: red;
}
使用计算属性即可把类名转换成组件内类名。
<script>
export default {
props: {
type: {
type: String,
default: 'default'
}
},
// 不同type对应不同类名
computed: {
typeClass () {
return `z-${this.type}`
}
}
}
</script>
最后在button上绑定一下typeClass,:class="[typeClass]"
,数组的形式为了后面绑定其他类型类名使用。
同理,一个button组件还应该有size类名,具体使用和type一样。同时,为了更好的用户体样,还可以在接收父传参的时候可以验证一下,并抛出错误信息。
size: {
type: String,
default: 'default',
// 参数校验
validator: function (value) {
// value是当前传来的值
const sizeList = ['small', 'large', 'default']
// 返回错误信息
return sizeList.includes(value)
}
}
随后是实现按钮事件
事件如果写到原生支持的标签身上会被直接识别为原生事件
<button @click="handlder">a</button>
; 事件如果写到自定义组件身上默认状态会被识别为自定义事件<z-button @click="handlder"></z-button>
想要解决组件身上的事件不能触发有下面2个方法。
- 增加.native修饰符
@click.native="handlder"
可以让vue系统帮助我们把事件绑定成为浏览器支持的原生事件 - 就当成自定义事件识别,然后按照父子通信的手段通过子组件内事件触发然后调用
$emit
方法触发即可
父
<Zbutton size="large" @get-click="clickIt" type="danger">danger</Zbutton>
clickIt (e) {
console.log('click it', e)
}
子
<button class="z-default" :class="[typeClass,sizeClass]" @click="clickHeadler">
<slot/>
</button>
methods: {
clickHeadler (e) {
// 触发父组件传下来的自定义事件
this.$emit('get-click', e)
}
}
z-editor组件
借助第三方组件进行二次开发,借助wangeditor
,而我们实现也是要实现最基本的v-model,数据显示以及回显。
这就不得不说一下v-model语法糖了。
v-model语法糖
v-model是父传子value+自定义事件input的语法糖,是v-band和v-on的简洁写法。
父
<Zeditor v-model="msg"/>
子
props: {
value: {
type: String
}
},
init () {
// 编辑器初始化
const editor = new E(this.$refs.editor)
editor.create()
editor.txt.html(this.value) // 这里就是数据显示的操作,api是第三方内置的api
}
有了数据显示就得有数据回显,查看第三方组件的文档能找到对应的监听事件,当props变化时,会自动触发那个事件,同时,还应该自己定义一下,手动监听一下$watch('value', ()=>{})。
为什么用$watch() 而不是watch配置项?
$watch
方法和watch
配置项内部实现的核心原理是一致的,但是$watch
更加灵活,它并不是组件已进行初始化就立刻监听的,而是在某个时刻你想要监听的时候才进行的监听。
<template>
<div ref="editor"></div>
</template>
<script>
import E from 'wangeditor'
export default {
props: {
value: {
type: String
}
},
methods: {
init () {
// 编辑器初始化
const editor = new E(this.$refs.editor)
editor.config.onchange = (newHtml) => {
this.$emit('input', newHtml)
}
editor.create()
editor.txt.html(this.value)
// 内置事件,手动监听数据
this.$watch('value', () => {
editor.txt.html(this.value)
})
}
},
mounted () {
this.init()
}
}
</script>
总结
- 实际开发中可能会根据业务借助三方成熟的插件修改成我们自己的vue组件
- 在自己的组件中把三方插件的功能按api实现出来,然后暴露一些vue组件的api供用户使用
- 组件身上添加v-model一般用于组件内部有可输入的控件,比如说input textarea内容编辑 ,目的是为了实现双向绑定
- 一旦组件身上写了v-model之后相当于:①名称为value的自定义属性的绑定②名称为input自定义事件
<Editor v-model/> === <Editor :value="xx1" @input="xx1" />
- 父子传参中通过定义
props:{value{}}
来接受传下来的数据 - 父子传参中﹐通过触发
$emit( "input ','子组件数据')
实现将子组件的数据传到父组件中 $watch
方法和watch
配置项内部实现的核心原理是一致的,但是$watch
更加灵活,它并不是组件已进行初始化就立刻监听的,而是在某个时刻你想要监听的时候才进行的监听。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情