5分钟实现一个Tag-Input(标签)组件

前言

本文是wo写组件设计的第一篇文章(处女作),之所以会写组件设计相关的文章,是因为作为一名优秀的前端工程师,面对各种繁琐而重复的工作,我们不应该按部就班的去辛(dao)勤(gen)劳(huo)动(zhong),而是要根据已有前端的开发经验,总结出一套自己的高效开发的方法。作为数据驱动的领导者vue等MVVM框架的出现,帮我们减少了工作中大量的冗余代码,一切皆组件的思想深得人心。所以,为了让工程师们有更多的时间去考虑业务和产品迭代,我们不得不掌握高质量组件设计的思路和方法。所以笔者将花时间去总结各种业务场景下的组件的设计思路和方法,并用原生框架的语法去实现各种常用组件的开发,希望等让前端新手或者有一定工作经验的朋友能有所收获。

正文

在开始组件设计之前希望大家对css3js有一定的基础。我们先看看实现后的组件效果:TagInput是一种可编辑的输入框,通过回车或者空格分割每个标签,用 vue来实现还是比较简单的。

先看效果图,下面会一步一步实现他。由视频演示可以知道tag-input组件可以自定义颜色主题(color theme), 可以手动关闭标签。

组件设计思路

我们第一步是要确认需求,一个tag标签组件一般都会有如下需求点:

  1. 可以改变标签颜色
  2. 提供关闭标签的配置,让用户可以关闭标签

需求收集好之后,作为一个有追求的程序员,会得出如下线框图:


vue有自带的属性检测方式,这里就不介绍了.

开工

注:以下代码需要vue-cli环境才能执行

新建文件夹及相关文件

src/components/目录中创建Tag-Input目录,并且创建Tag-Input.vue文件和index.js文件。如下图:


布局

搭建基本结构:

<template><div class="tag-input">

  <div class="tag-item" v-for="item in tags" :key="item">{{ item }}div>

  <input class="tag-input" @keyup.space="generateTag" v-model="value" type="text">div>template>

书写基本逻辑:

  1. 在组件内部维护一个tags数组默认为空数组
  2. 在组件内部维护一个value字符串默认为空字符串
  3. 书写一个方法generateTag,绑定给inputkeyup事件并且给定修饰符为space/enter,当输入为合法字符串后,将当前的valuepushtags中 通过v-for循环出来。

代码如下:

export default {  name: 'Tag-Input',  data () {    return {      tags: [],      value: ''    }  },  methods: {    generateTag () {    // 判定value是否合法 不能唯空      if (this.value.trim().length > 0) {        this.tags.push(this.value)      }      // 还原input的输入状态      this.value = ''    }  }}

外观

我们让循环出来的taginput出于同一行内,并且去掉input的border/out-line/和background,让最外层的div.tag-input被模拟成一个input的感觉。

个人觉得element-ui的tag组件蛮漂亮的,所以借鉴。毕竟读书人不能叫窃取而是叫借鉴。传送门


.tag-input-warp{    width: 80%;    height: 150px;    border-radius: 5px;    border: 1px solid #666;    margin: auto;    padding: 24px;  }  .tag-item, .tag-input{    display: inline-block;  }  .tag-item{    padding: 10px 14px;    font-size: 14px;    background-color: #f2f9ec;    color: #84c259;    border: 1px solid #e4fada;    text-align: center;    margin: 6px;    /*vertical-align: middle;*/  }  .tag-input{    border: none;    outline: none;  }  .tag-text{    vertical-align: middle;  }  .tag-icon__close{    cursor: pointer;    vertical-align: middle;    display: inline-block;    width: 16px;    height: 16px;    background-size: contain;    background-repeat: no-repeat;    background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgEAYAAAAj6qa3AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAAASAAAAEgARslrPgAAAjdJREFUaN7t1t9LU2EcBvDndRtKR6YX4UQCJevCi26k6CI0vYluBAeObZgEUdFNSjfhRNtGh04qBHUKN6iLfkjtUFANTE7E8OxClzLIbqSZrMARNEr6gTr1vF2tiyLQ9e5sg/fzB7x8n4fzft8DcBzHcRzHcWwEA3OzZ89YLKzP9dJYY/d5q/Wq9FJ1dFVVsTq3jN2AEXqSVld/vrE68P3T/Pzl5mizO9jZySq4+UPGps9MTm7uqrCb5WCw6Arwk3Zyl6ysYJYeAhSFpOgJDCmK+Cr6zXXJbt/peaP31AM9NYJgebC+sHUhHCbPqBVf6+pMvZs/9Nr+flZz5434Uxtwd/j9Yq12zV2TyWy3iGxw8b624VqamhKva8fd+5JJiUaokzY0FDpX3oooVHBidBFoxG7EPB6Mk9P0nNNZvrx6xBJQ1XVSEd+YmZjAF3SQY/X1pt6tF3qirc1D2kmIJJMlX8A/i9iD/fRdIoEe3CIHBcGo4FnMluB2lT9ZC5tjIyPwkCVYUym8xRsSbWoqG6c34ZAko4IbXkD2jv/+1EEXAQCn8JTKsqx/JM9xR5ZzfTWKtoC/gv9xxwfHWuceqX19eI80DksSuultEgiFjC4ib8F3utVzfT6LRvbPTfRpR13R6elcn7OSK4JVcKOLYLYDzBfXxnTRZoOAxySl61hAmu5tafnfrT4otF55GPZ68ZosIj48jFEaJ2mfT1EUxeEwmVjNXzK8NEIdXZWVhZ6D4ziO47jS9wur727+lgG2ewAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMC0wNS0yOFQyMjowMzoyNiswODowMBt9NI0AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjAtMDUtMjhUMjI6MDM6MjYrMDg6MDBqIIwxAAAASHRFWHRzdmc6YmFzZS11cmkAZmlsZTovLy9ob21lL2FkbWluL2ljb24tZm9udC90bXAvaWNvbl92dXY4bmVpeTFjL2NoYWhhby5zdmc0h1nOAAAAAElFTkSuQmCC");  }

实际效果如下:


感觉还行。。。

v-model语法糖

把内部的tag传递出去:

Vue内置了v-model指令,v-model 是一个语法糖,可以拆解为 props: value 和 events: input。就是说组件只要提供一个名为 value 的 prop,以及名为 input 的自定义事件,满足这两个条件,使用者就能在自定义组件上使用 v-model;

// v-model语法糖 关键this.$emit('input', this.tags)
// 使用方法<tag-input v-model="res">// 通过res获取内部状态

组件的export

相信很多人在用Vue使用别人的组件时,会用到 Vue.use() 。例如:Vue.use(VueRouter)、Vue.use(MintUI)。那这是为什么呐?

接下来我们自定义一个需要 Vue.use() 的组件,也就是有 install 的组件。

// index.jsimport TagInput from './Tag-Input.vue';

/* istanbul ignore next */TagInput.install = function(Vue) {  Vue.component(TagInput.name, TagInput);};

export default TagInput;

Tag-Input的全局注册

// 引入组件import TagInput from '@/components/Tag-Input';Vue.use(TagInput)

完整代码

<template><div class="tag-input-warp">

  <div class="tag-item" v-for="(item, index) in tags" :key="index">    <span class="tag-text">{{ item }}span>    <span class="tag-icon__close" @click="deleteTagByIndex(index)">span>  div>

  <input class="tag-input" @keyup.space="generateTag" autofocus v-model="value" type="text">div>template>

<script>export default {name: 'Tag-Input',  data () {return {tags: [],value: ''    }  },methods: {    generateTag () {if (this.value.trim().length > 0) {this.tags.push(this.value)// v-model语法糖 关键this.$emit('input', this.tags)      }this.value = ''    },    deleteTagByIndex (index) {this.tags.splice(index, 1)    }  }}script>

<style scoped>.tag-input-warp{width: 80%;height: 150px;border-radius: 5px;border: 1px solid #666;margin: auto;padding: 24px;  }.tag-item, .tag-input{display: inline-block;  }.tag-item{padding: 10px 14px;font-size: 14px;background-color: #f2f9ec;color: #84c259;border: 1px solid #e4fada;text-align: center;margin: 6px;/*vertical-align: middle;*/  }.tag-input{border: none;outline: none;color: #666666;  }.tag-text{vertical-align: middle;  }.tag-icon__close{cursor: pointer;vertical-align: middle;display: inline-block;width: 16px;height: 16px;background-size: contain;background-repeat: no-repeat;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgEAYAAAAj6qa3AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAAASAAAAEgARslrPgAAAjdJREFUaN7t1t9LU2EcBvDndRtKR6YX4UQCJevCi26k6CI0vYluBAeObZgEUdFNSjfhRNtGh04qBHUKN6iLfkjtUFANTE7E8OxClzLIbqSZrMARNEr6gTr1vF2tiyLQ9e5sg/fzB7x8n4fzft8DcBzHcRzHcWwEA3OzZ89YLKzP9dJYY/d5q/Wq9FJ1dFVVsTq3jN2AEXqSVld/vrE68P3T/Pzl5mizO9jZySq4+UPGps9MTm7uqrCb5WCw6Arwk3Zyl6ysYJYeAhSFpOgJDCmK+Cr6zXXJbt/peaP31AM9NYJgebC+sHUhHCbPqBVf6+pMvZs/9Nr+flZz5434Uxtwd/j9Yq12zV2TyWy3iGxw8b624VqamhKva8fd+5JJiUaokzY0FDpX3oooVHBidBFoxG7EPB6Mk9P0nNNZvrx6xBJQ1XVSEd+YmZjAF3SQY/X1pt6tF3qirc1D2kmIJJMlX8A/i9iD/fRdIoEe3CIHBcGo4FnMluB2lT9ZC5tjIyPwkCVYUym8xRsSbWoqG6c34ZAko4IbXkD2jv/+1EEXAQCn8JTKsqx/JM9xR5ZzfTWKtoC/gv9xxwfHWuceqX19eI80DksSuultEgiFjC4ib8F3utVzfT6LRvbPTfRpR13R6elcn7OSK4JVcKOLYLYDzBfXxnTRZoOAxySl61hAmu5tafnfrT4otF55GPZ68ZosIj48jFEaJ2mfT1EUxeEwmVjNXzK8NEIdXZWVhZ6D4ziO47jS9wur727+lgG2ewAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMC0wNS0yOFQyMjowMzoyNiswODowMBt9NI0AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjAtMDUtMjhUMjI6MDM6MjYrMDg6MDBqIIwxAAAASHRFWHRzdmc6YmFzZS11cmkAZmlsZTovLy9ob21lL2FkbWluL2ljb24tZm9udC90bXAvaWNvbl92dXY4bmVpeTFjL2NoYWhhby5zdmc0h1nOAAAAAElFTkSuQmCC");  }style>

写在最后

本文写到这里其实还有一些功能没有实现,希望大家留言讨论;后续我将会继续发布button/dialog/icon/toast等等的组件的包教不包会系列, 来复盘我多年的组件化之旅。欢迎各位转发收藏。

vue 字符串分割_嗯哼vue组件taginput包教不包会相关推荐

  1. vue java 插件开发_实习模块vue+java小型全栈开发(三)

    实习模块vue+java小型全栈开发(三) --dx 背景 首先,先给自己一个答案:这篇博客我定义为(三),因为之前的两个模块页面,内容都是一样的,但是被改了几次需求,就一直拖着没有上传. 今天是真正 ...

  2. vue 全局排序_搞定VUE [ 一 ]

    击上方  蓝字  关注我 首先.以我个人的观点,不赞成把这些东西死记下来,会使用,能上手做,有不明白的及时的去浏览.翻阅,在实战中去快速的理解和掌握,之后水到渠成式的一步步去走向深入.当然,从自身的职 ...

  3. vue 生命周期_深入理解Vue实例生命周期

    ‍vue实例生命周期与生命周期钩子‍ 每个 Vue 实 例在被创建时都会经过一系列的初始化过程.例如,需要设置数据监听.编译模板.将实例挂载到 DOM 并在数据变化时更新 DOM 等. 为了让开发者在 ...

  4. vue 数组长度_深入理解Vue的数据响应式

    什么是响应式 当一个物体对外界的变化做出反应就叫响应式的,如"我打你一拳,你会喊疼". Vue的数据响应式 就是对数据做出改变时,视图上也会做出相应的变化. 举个例子 1const ...

  5. python 字符串分割_如何使用python语言split方法对不同字符串分割

    在JavaScript中,可以使用split()将字符串分割成字符串数组:而在python语言中,split()方法也可以将字符串进行分割,分割之后的结果放置在列表中.下面利用几个实例说明split( ...

  6. vue 新手指引_精通react/vue组件设计之快速实现一个可定制的进度条组件

    前言 这篇文章是笔者写组件设计的第四篇文章,之所以会写组件设计相关的文章,是因为作为一名前端优秀的前端工程师,面对各种繁琐而重复的工作,我们不应该按部就班的去"辛勤劳动",而是要根 ...

  7. render vue 添加类_详解vue 动态加载并注册组件且通过 render动态创建该组件

    基于 iview Tabs 组件实现 功能:为每个 tab 动态创建不同的.特定的组件内容,而不需要大量的 import 组件并进行 component 注册 Index.vue import loa ...

  8. vue 日期面板_手写Vue日历组件

    export class Lunar {//初一显示月份 //节日按照优先级替换日 private dataObj: any ={ month:"", day:"&quo ...

  9. vue制作日历_如何使用Vue制作每月日历

    vue制作日历 Have you ever seen a calendar on a webpage and thought, how the heck did they did that? For ...

最新文章

  1. 科普|深度解析5G与未来天线技术
  2. Linux安装GitLib
  3. 6-2 链式表的按序号查找
  4. HTTP basic auth
  5. 三星要用Exynos 9芯片打造独立VR头显
  6. spring jms 事务_Spring JMS:处理事务中的消息
  7. mfc对话框在不同计算机上显示不全
  8. lightswitch 添加 TreeView 控件
  9. python3 缺少PIP解决办法
  10. Linux下文件系统目录结构
  11. springboot 没有找到service_Spring Boot 应用程序五种部署方式
  12. 重磅!2020 年算法工程师技术路线图
  13. 【版本控制工具】svn服务器、客户端安装配置及eclipse的svn检出
  14. directx修复工具win7_win7蓝屏该怎么解决图文教程
  15. 微信公众号支付功能开发
  16. 广东地区经纬度Python版
  17. MATLAB | 绘图复刻(二) | 折线图+误差棒+柱状图+散点抖动+灰色背景+图片叠加
  18. 前端css解决z-index 上层元素遮挡下层元素的方法
  19. 南开大学20春计算机应用基础在线作业,南开大学20春学期计算机应用基础在线作业参考答案...
  20. (嵌入式)关于arm中的存储控制器

热门文章

  1. 【渝粤教育】电大中专新媒体营销实务 (13)作业 题库
  2. 2021年春季学期期末统一考试 劳动与社会保障法(本) 试题
  3. matlab 矩阵jocobi迭代_高校MATLAB被禁用,掀起中国本土软件脆弱的冰山一角
  4. oracle 邻接模型,【原创】MySQL 模拟Oracle邻接模型树形处理
  5. python怎么输入两行_python交互模式下输入换行/输入多行命令的方法
  6. Java实现复数Complex的加减乘除运算、取模、求幅角角度
  7. html selsec 文字靠右,EDA课程设计
  8. C语言去括号编程题,去括号 - C语言网
  9. Java构建子类对象时的顺序
  10. java 生成校验验证码_java 验证码生成与校验