组件开发初体验

31 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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个方法。

  1. 增加.native修饰符 @click.native="handlder" 可以让vue系统帮助我们把事件绑定成为浏览器支持的原生事件
  2. 就当成自定义事件识别,然后按照父子通信的手段通过子组件内事件触发然后调用$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 天,点击查看活动详情