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 相关文章推荐
解决extjs在firefox中关闭窗口再打开后iframe中js函数访问不到的问题
Nov 06 Javascript
使用javascript:将其它类型值转换成布尔类型值的解决方法详解
May 07 Javascript
jQuery学习笔记之总体架构
Jun 03 Javascript
seaJs的模块定义和模块加载浅析
Jun 06 Javascript
js的touch事件的实际引用
Oct 13 Javascript
jQuery中prepend()方法用法实例
Dec 25 Javascript
微信小程序 向左滑动删除功能的实现
Mar 10 Javascript
基于 webpack2 实现的多入口项目脚手架详解
Jun 26 Javascript
详谈js模块化规范
Jul 07 Javascript
React Component存在的几种形式详解
Nov 06 Javascript
Vue实现商品飞入购物车效果(电商项目)
Nov 26 Javascript
JS自定义右键菜单实现代码解析
Jul 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
Thinkphp的volist标签嵌套循环使用教程
2014/07/08 PHP
php继承中方法重载(覆盖)的应用场合
2015/02/09 PHP
Gambit vs CL BO3 第三场 2.13
2021/03/10 DOTA
使Ext的Template可以解析二层的json数据的方法
2007/12/22 Javascript
javascript new一个对象的实质
2010/01/07 Javascript
javascript Array数组对象的扩展函数代码
2010/05/22 Javascript
javascript比较两个日期的先后示例代码
2014/12/31 Javascript
jQuery判断元素上是否绑定了指定事件的方法
2015/03/17 Javascript
jquery马赛克拼接翻转效果代码分享
2015/08/24 Javascript
BootStrap 智能表单实战系列(五) 表单依赖插件处理
2016/06/13 Javascript
JavaScript提高网站性能优化的建议(二)
2016/07/24 Javascript
详解微信小程序 wx.uploadFile 的编码坑
2017/01/23 Javascript
Node.js获取前端ajax提交的request信息
2017/02/20 Javascript
vue中简单弹框dialog的实现方法
2018/02/26 Javascript
Angular学习笔记之集成三方UI框架、控件的示例
2018/03/23 Javascript
原生js拖拽实现图形伸缩效果
2020/02/10 Javascript
vue基于Echarts的拖拽数据可视化功能实现
2020/12/04 Vue.js
基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件功能
2021/02/23 Vue.js
windows下安装Python和pip终极图文教程
2017/03/05 Python
python定时利用QQ邮件发送天气预报的实例
2017/11/17 Python
Python线程创建和终止实例代码
2018/01/20 Python
python函数的万能参数传参详解
2019/07/26 Python
Python3网络爬虫开发实战之极验滑动验证码的识别
2019/08/02 Python
Pytorch中的variable, tensor与numpy相互转化的方法
2019/10/10 Python
用OpenCV将视频分解成单帧图片,图片合成视频示例
2019/12/10 Python
Python爬虫HTPP请求方法有哪些
2020/06/03 Python
HTML5页面无缝闪开的问题及解决方案
2020/06/11 HTML / CSS
高级护理实习生自荐信
2013/09/28 职场文书
夜班门卫岗位职责
2013/12/09 职场文书
小学生家长评语集锦
2014/01/30 职场文书
《唯一的听众》教学反思
2014/02/20 职场文书
2015年党日活动总结范文
2015/03/25 职场文书
2015年林业工作总结
2015/05/14 职场文书
校长新学期寄语2016
2015/12/04 职场文书
Python超简单容易上手的画图工具库推荐
2021/05/10 Python
Oracle11g r2 卸载干净重装的详细教程(亲测有效已重装过)
2021/06/04 Oracle