vue组件系列之TagsInput详解


Posted in Javascript onMay 14, 2020

简介

TagsInput 是一种可编辑的输入框,通过回车或者分号来分割每个标签,用回退键删除上一个标签。用 vue 来实现还是比较简单的。

先看效果图,下面会一步一步实现他。

vue组件系列之TagsInput详解

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

(一)伪造一个输入框

因为单行的文本框只能展示纯文本,所以图里面的标签实际上都是 html元素,用vue模板来写的话,是这样的:

<template>
<div class="muli-tags" @click='focus'>
 <button class='btn' v-for='(tag, index) in tags' :key='index'>
 {{tag}}
 </button>
 <input type="text" ref='input' v-model='current'>
</div>
</template>

<script>
export default {
 name: 'TagsInput',
 methods: {
 focus () {
 this.$refs.input.focus()
 },
 },
 data () {
 return {
 tags: [],
 current: ''
 }
 }
}
</script>

<style lang='less'>
 .muli-tags{
 padding: 5px 10px;
 display: block;
 border: 1px solid #ccc;
 input{
 background: transparent;
 }
 }
 .btn{
 margin: 0 5px 3px 0;
 padding: 4px 5px;
 background: #fff;
 border: 1px solid #eee;
 box-shadow: 0 0 4px;
 }
</style>

(二)监听输入

在伪造好一个输入框之后,我们对输入框的事件进行处理,

  • 回车和逗号会把input的值添加到tags数组,然后清空input
  • 添加值之前,判断tags数组是否已经包含同名的值
  • 按回退键,删除最近的一个标签
// @keydown.188 188代表是是分号键的keyCode
<input type="text"
 ref='input'
 @keyup.enter="add"
 @keydown.delete="del"
 @keydown.188='split'
 v-model='current'>
 
methods: {
 // 按下分号键的时候,需要阻止默认事件,否则会出现分号
 split (e) {
 e.preventDefault()
 this.add(e)
 },
 add (e) {
 const val = e.target.value
 if (!val) return
 // 如果已经存在相同tag,不再添加
 if (this.tags.indexOf(val) > -1) return
 // 把输入值添加到tag,并清空文本框
 this.tags.push(val)
 this.current = ''
 },
 del (e) {
 // 当文本框内没有值,再按回退键,则删除最后一个tag
 if (!e.target.value.length) {
 this.tags.pop()
 }
 },
}

(三)删除标签

前面都是通过键盘来操作标签,鼠标点击标签应该也是可以删除的

<button class='btn' v-for='(tag, index) in tags' :key='index' @click='delTag(index)'>{{tag}} <span>x</span></button>

methods: {
 // 删除点击的标签
 delTag (index) {
 this.tags.splice(index, 1)
 }
}

(四)自定义 v-model

通过上面的步骤,一个 tagsinput 组件就已经做好了,再给他添加自定义的 v-model ,让他可以像input一样响应表单数据。

// props
 props: {
 value: Array,
 required: true,
 default: () => []
 }
 
 // computed
 computed: {
 tags () {
 return this.value.slice()
 }
 }
 
 // methods
 methods: {
 // 删除点击的标签
 delTag (index) {
 this.tags.splice(index, 1)
 this.$emit('input', this.tags)
 }
 }

(五)完整代码

// TagsInput.vue
<template>
 <div class="muli-tags" @click='focus'>
 <button class='btn' v-for='(tag, index) in tags' :key='index' @click='delTag(index)'>{{tag}} <span>x</span></button>
 <input type="text"
 ref='input'
 @keyup.enter="add"
 @keydown.delete="del"
 @keydown.188='split'
 v-model='current'>
 </div>
</template>

<script>
export default {
 props: {
 value: Array,
 required: true,
 default: () => []
 },
 methods: {
 focus () {
 this.$refs.input.focus()
 },
 split (e) {
 e.preventDefault()
 this.add(e)
 },
 add (e) {
 const val = e.target.value
 if (!val) return
 if (this.tags.indexOf(val) > -1) return
 this.tags.push(val)
 this.$emit('input', this.tags)
 this.current = ''
 },
 del (e) {
 if (!e.target.value.length) {
 this.tags.pop()
 this.$emit('input', this.tags)
 }
 },
 delTag (index) {
 this.tags.splice(index, 1)
 this.$emit('input', this.tags)
 }
 },
 computed: {
 tags () {
 return this.value.slice()
 }
 },
 data () {
 return {
 current: ''
 }
 }
}
</script>

<style lang='less'>
.muli-tags{
 padding: 5px 10px;
 display: block;
 border: 1px solid #ccc;
 input{
 background: transparent;
 }
 .btn{
 margin: 0 5px 3px 0;
 padding: 4px 5px;
 background: #fff;
 border: 1px solid #eee;
 box-shadow: 0 0 4px;
 }
}
</style>

作为组件被调用,这样就可以看到像文章开头那幅图一样的组件了。

// 父组件
<template>
 <tags-input v-model='tags'/>
</template>
<script>
import TagsInput from './TagsInput.vue'
export default {
 components: {
 TagsInput
 },
 data () {
 return {
 tags: ['tag1', 'tag2', 'tag3']
 }
 }
}
</script>

总结

到此这篇关于vue组件TagsInput的文章就介绍到这了,更多相关vue组件TagsInput内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
Javascript执行效率全面总结
Nov 04 Javascript
删除javascript中注释语句的正则表达式
Jun 11 Javascript
基于jQuery 实现bootstrapValidator下的全局验证
Dec 07 Javascript
AngularJS 指令详细介绍
Jul 27 Javascript
超实用的javascript时间处理总结
Aug 16 Javascript
D3.js封装文本实现自动换行和旋转平移等功能
Oct 14 Javascript
使用jQuery.Pin垂直滚动时固定导航
May 24 jQuery
Vue应用部署到服务器的正确方式
Jul 15 Javascript
Javascript实现运算符重载详解
Apr 07 Javascript
Vue实现todolist删除功能
Jun 26 Javascript
使用layui+ajax实现简单的菜单权限管理及排序的方法
Sep 10 Javascript
VsCode里的Vue模板的实现
Aug 12 Javascript
ant-design-vue按需加载的坑的解决
May 14 #Javascript
JavaScript数组排序功能简单实现
May 14 #Javascript
Typescript3.9 常用新特性一览(推荐)
May 14 #Javascript
Node.js API详解之 Error模块用法实例分析
May 14 #Javascript
微信小程序 获取手机号 JavaScript解密示例代码详解
May 14 #Javascript
JavaScript, select标签元素左右移动功能实现
May 14 #Javascript
vue实现商品列表的添加删除实例讲解
May 14 #Javascript
You might like
sqlyog 中文乱码问题的设置方法
2008/10/19 PHP
POSIX 风格和兼容 Perl 风格两种正则表达式主要函数的类比(preg_match, preg_replace, ereg, ereg_replace)
2010/10/12 PHP
PHP四种基本排序算法示例
2015/04/09 PHP
详谈PHP程序Laravel 5框架的优化技巧
2016/07/18 PHP
什么是PHP文件?如何打开PHP文件?
2017/06/27 PHP
PHP中遍历数组的三种常用方法实例分析
2019/06/24 PHP
Laravel6.18.19如何优雅的切换发件账户
2020/06/14 PHP
ExtJS TabPanel beforeremove beforeclose使用说明
2010/03/31 Javascript
JS获得浏览器版本和操作系统版本的例子
2014/05/13 Javascript
jQuery ui实现动感的圆角渐变网站导航菜单效果代码
2015/08/26 Javascript
javascript移动开发中touch触摸事件详解
2016/03/18 Javascript
JavaScript 数组- Array的方法总结(推荐)
2016/07/21 Javascript
基于jquery二维码生成插件qrcode
2017/01/07 Javascript
微信小程序组件 contact-button(客服会话按钮)详解及实例代码
2017/01/10 Javascript
详解Vue中添加过渡效果
2017/03/20 Javascript
Three.js利用Detector.js插件如何实现兼容性检测详解
2017/09/26 Javascript
Express下采用bcryptjs进行密码加密的方法
2018/02/07 Javascript
vue 1.0 结合animate.css定义动画效果
2018/07/11 Javascript
jQuery使用$.extend(true,object1, object2);实现深拷贝对象的方法分析
2019/03/06 jQuery
Vue-cli3.X使用px2 rem遇到的问题及解决方法
2019/08/08 Javascript
在Echarts图中给坐标轴加一个标识线markLine
2020/07/20 Javascript
基于vue项目设置resolves.alias: '@'路径并适配webstorm
2020/12/02 Vue.js
python获取标准北京时间的方法
2015/03/24 Python
python网络爬虫学习笔记(1)
2018/04/09 Python
Python 实现数据结构-循环队列的操作方法
2019/07/17 Python
Pycharm操作Git及GitHub的步骤详解
2020/10/27 Python
Python使用windows设置定时执行脚本
2020/11/12 Python
浅析HTML5中的download属性使用
2019/03/13 HTML / CSS
中国专业的音频分享平台:喜马拉雅
2019/05/24 全球购物
如何在发生故障的节点上重新安装 SQL Server
2013/03/14 面试题
幼儿园教师备课制度
2014/01/12 职场文书
旅游个人求职信范文
2014/01/30 职场文书
护理专科自荐书范文
2014/02/18 职场文书
教师工作失职检讨书
2014/09/18 职场文书
水知道答案观后感
2015/06/08 职场文书
小学体育组工作总结
2015/08/13 职场文书