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 相关文章推荐
setTimeout和setInterval的浏览器兼容性分析
Feb 27 Javascript
JavaScript 设计模式 富有表现力的Javascript(一)
May 26 Javascript
web css实现整站样式互相切换
Oct 29 Javascript
原生JavaScript实现连连看游戏(附源码)
Nov 05 Javascript
JS解析XML实例分析
Jan 30 Javascript
JS操作XML实例总结(加载与解析XML文件、字符串)
Dec 08 Javascript
Javascript别踩白块儿(钢琴块儿)小游戏实现代码
Jul 20 Javascript
JS解决IOS中拍照图片预览旋转90度BUG的问题
Sep 13 Javascript
vue 弹框产生的滚动穿透问题的解决
Sep 21 Javascript
深入浅析javascript函数中with
Oct 28 Javascript
利用Vconsole和Fillder进行移动端抓包调试方法
Mar 05 Javascript
vue 自定指令生成uuid滚动监听达到tab表格吸顶效果的代码
Sep 16 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
PHP上传Excel文件导入数据到MySQL数据库示例
2016/10/25 PHP
php+javascript实现的动态显示服务器运行程序进度条功能示例
2017/08/07 PHP
详解cookie验证的php应用的一种SSO解决办法
2017/10/20 PHP
RR vs IO BO3 第一场2.13
2021/03/10 DOTA
js正确获取元素样式详解
2009/08/07 Javascript
JavaScript中的面向对象介绍
2012/06/30 Javascript
window.open不被拦截的实现代码
2012/08/22 Javascript
JSON无限折叠菜单编写实例
2013/12/16 Javascript
jQuery如何实现点击页面获得当前点击元素的id或其他信息
2014/01/09 Javascript
javascript实现获取服务器时间
2015/05/19 Javascript
JavaScript中对DOM节点的访问、创建、修改、删除
2015/11/16 Javascript
谈谈jQuery Ajax用法详解
2015/11/27 Javascript
JavaScript模拟数组合并concat
2016/03/06 Javascript
基于jQuery的Web上传插件Uploadify使用示例
2016/05/19 Javascript
JSON中key动态设置及JSON.parse和JSON.stringify()的区别
2016/12/29 Javascript
基于Bootstrap表单验证功能
2017/11/17 Javascript
20道JS原理题助你面试一臂之力(必看)
2019/07/22 Javascript
微信自定义分享链接信息(标题,图片和内容)实现过程详解
2019/09/04 Javascript
使用Vue-cli3.0创建的项目 如何发布npm包
2019/10/10 Javascript
[01:51]2014DOTA2西雅图邀请赛 MVP 外卡赛black场间采访
2014/07/09 DOTA
在Ubuntu系统下安装使用Python的GUI工具wxPython
2016/02/18 Python
Python3中的json模块使用详解
2018/05/05 Python
Python 微信爬虫完整实例【单线程与多线程】
2019/07/06 Python
开启Django博客的RSS功能的实现方法
2020/02/17 Python
如何配置关联Python 解释器 Anaconda的教程(图解)
2020/04/30 Python
Python可以实现栈的结构吗
2020/05/27 Python
天猫超市:阿里巴巴打造的网上超市
2016/11/02 全球购物
汽车制造与装配专业自荐信范文
2014/01/02 职场文书
大学毕业感言
2014/01/10 职场文书
生产部管理制度
2014/01/31 职场文书
应届中专生自荐书范文
2014/02/13 职场文书
二年级小学生评语
2014/04/21 职场文书
放弃继承权公证书
2015/01/23 职场文书
工程质检员岗位职责
2015/04/08 职场文书
Java生成读取条形码和二维码的简单示例
2021/07/09 Java/Android
Redis安装使用RedisJSON模块的方法
2022/03/23 Redis