「站在上帝的角度」谈谈Element组件结构-Input

简介: 「站在上帝的角度」谈谈Element组件结构-Input

👋 前言


  • 用户就是上帝,站在上帝的角度也就是站在使用者的角度去看待组件。
  • 用过不少优秀的UI库,用的时候美滋滋,轮到自己搭组件库的时候往往会去参考别人的源码。
  • 看完源码后恍然大悟 噢!原来可以这样写,但心里难免会有疑惑别人是怎么想出来这种解决思路的?🤳
  • 这一系列文章主要是面向未理解或者有疑惑的同学所以讲的比较基础,就让我们站在用户的角度去思考结构,看看换一种思路去写代码是不是有变化?


⌨️关于Input组件


👻为什么我们会用到Input


👨‍💼 作为用户

  • input输入框是最常见的一种表单输入的控件,一般出现在问卷或者后台系统里面作为一个可以表达的组件。
  • 用户需要的输入框无非就是简洁好看的,如果搞的花里胡哨可能会有些不适应,特别是政务系统里面的表单更是需要同一色号。


👨‍💻 作为组件库使用者

  • 我们可以看到很多的组件库都有Input,相信大家都很熟悉了。
  • 当我们将组件库的Input组件放到我们的页面我们想要的效果是什么?
  • 可以实现输入的功能
  • 拥有原生input的所有功能
  • 可以满足基本的双向绑定
  • 可以在基本的需求上进行定制增加功能(比如: 禁用添加图标清空
  • 在某一个方面来说,Input的出现也让我们在制作页面时更加方便统一样式和功能,节省不少时间


⚒️ 搭建组件


接下来可能用尽可能少的代码搭配element的源码进行结构说明,配合element Input源码食用更加美味喔


🔨 基本架子

  • 要设计一个上图这种的Input不难,其实就是修改一下input的样式罢了
  • 总结起来总共也只有4个要点
  • 准备一个外部的容器包含input
  • 根据不同类型呈现texttextarea等类型的输入框
  • input可以使用原生的属性,例如(placeholder

<template>
  <div class="zl-input">
    <template v-if="type !== 'textarea'">
      <input ref="input" type="text" class="zl-input__inner" v-bind="$attrs">
    </template>
    <template v-else>
      <textarea ref="textarea"></textarea>
    </template>
  </div>
</template>
...
<script>
export default {
    props:{
        value: [String, Number],
        type: {
          type: String,
          default: 'text'
        }
       }
    };
</script>
...
复制代码
  • 以上就是element最简单的input结构,可以看到子组件通过分辨type来分辨是input类型还是textarea类型,这两种不同类型需要做不同处理,v-bind="$attrs"可以将没有在props出现的属性直接给到input上就例如placeholder可以直接作为input的属性本文就主要讲一讲input,两者其实没什么差别,关于具体样式可以看element 样式
  • 当然这只是一个架子我们还需要加上双向绑定和其他功能。


🎶 双向绑定

  • 单单只是一个架子可不行,我们需要记录下来输入的值,这时候就需要用到外面的v-model
  • 在父组件我们用v-model传入了一个值, 而v-model的语法糖会把这个值当成propsvalue传到子组件,子组件只要通过$emit时间改变外部的input事件就可以啦。
<template>
  <div class="zl-input">
    <template v-if="type !== 'textarea'">
      <input ref="input" type="text" class="zl-input__inner" v-bind="$attrs" @input="handleInput">
    </template>
    <template v-else>
      <textarea ref="textarea"></textarea>
    </template>
  </div>
</template>
···
   computed:{
    nativeInputValue() {
       return this.value === null || this.value === undefined ? '' : String(this.value);
     }
   },
   watch:{
     nativeInputValue() {
       this.setNativeInputValue();
     },
   },
   mounted () {
      this.setNativeInputValue();
   },
   methods:{
    handleInput(event) {
       this.$emit('input', event.target.value);
     },
    getInput() {
      return this.$refs.input || this.$refs.textarea;
    },
    setNativeInputValue() {
      const input = this.getInput();
      if (!input) return;
      if (input.value === this.nativeInputValue) return;
      input.value = this.nativeInputValue;
    },
   }
···
复制代码
  • 在这里要注意的是我们没有像往常做双向绑定一样直接在input绑定:value="xxx"而是通过手动赋值在setNativeInputValue控制外部传进来的value值,一开始看到element的源码的时候我也很疑惑?为什么要这样做,直接使用:value不是更方便吗,最后在一个issues找到了答案。

  • 意思大致就是elementinput组件在输入前后会有一些处理,而这些处理跟:value的模式冲突了,最后改成了手动赋值,如果我们自己写的组件没有这种bug的话两种方式都可以使用,就当是学到了一种方法吧。
  • 这样一来我们的一个最简单的input就做好了。


🧮 更多需求

  • 一个最简单的架子搭好了接下来就可以定制我们的组件了。
  • 比如说禁用啊,加图标啊,相信大家也已经很熟悉了,无非就是通过插槽获取通过props实现动态样式切换即可。
  • 除了样式的切换还加上了一些前置内容和后置内容插槽来便利使用者,实现也不难就是在不同的的地方加上具名插槽即可。
  • 在事件上也可以定制很多情况比如focusblur 这些都是在input绑定事件即可,更多的实现可以参考传送门进行学习~


👋 写在最后


  • 总的来说Input组件相对于其他复杂组件比较简单,只要把架子搭出来了剩下就是不断的优化加内容,大家也可以一起写写组件试试,难点在于合理制作双向绑定不跟其他事件冲突。
  • 对于组件库的搭建我也在慢慢的摸索,讲的都是我自己得出来的分享所以说可能对于大佬来说会比较基础,但我相信我的不断输出可以帮助到一些有疑惑的同学。
  • 如果您觉得这篇文章有帮助到您的的话不妨🍉关注+点赞+收藏+评论+转发🍉支持一下哟~~😛
相关文章
|
Cloud Native 算法 Go
技术面试与HR面:两者之间的关联与区别
技术面试与HR面:两者之间的关联与区别
341 0
|
存储 Java 程序员
【C#本质论 六】类-从设计的角度去认知(封装)(上)
【C#本质论 六】类-从设计的角度去认知(封装)(上)
108 0
|
编译器 C#
【C#本质论 六】类-从设计的角度去认知(封装)(下)
【C#本质论 六】类-从设计的角度去认知(封装)(下)
86 0
|
测试技术
软件测试面试题:如何使用xpath定位一个兄弟元素?
软件测试面试题:如何使用xpath定位一个兄弟元素?
197 0
|
JavaScript 测试技术
软件测试面试题:如何去定位属性动态变化的元素?
软件测试面试题:如何去定位属性动态变化的元素?
429 0
「站在上帝的角度」谈谈Element组件结构-Radio
「站在上帝的角度」谈谈Element组件结构-Radio
|
前端开发 iOS开发 容器
「站在上帝的角度」谈谈Element组件结构-Switch
「站在上帝的角度」谈谈Element组件结构-Switch
|
容器
「站在上帝的角度」谈谈Element组件结构-Rate
「站在上帝的角度」谈谈Element组件结构-Rate
|
开发者 容器
「站在上帝的角度」谈谈Element组件结构-InputNumber
「站在上帝的角度」谈谈Element组件结构-InputNumber
「站在上帝的角度」谈谈Element组件结构-Icon
「站在上帝的角度」谈谈Element组件结构-Icon