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 相关文章推荐
浅析return false的正确使用
Nov 04 Javascript
jQuery中closest()函数用法实例
Jan 07 Javascript
Bootstrap每天必学之基础排版
Nov 20 Javascript
jQuery实现图片预加载效果
Nov 27 Javascript
JS中闭包的经典用法小结(2则示例)
Dec 28 Javascript
100多个基础常用JS函数和语法集合大全
Feb 16 Javascript
jquery单击文字或图片内容放大并居中显示
Jun 23 jQuery
微信小程序tabBar底部导航中文注解api详解
Aug 16 Javascript
angularjs实现过滤并替换关键字小功能
Sep 19 Javascript
浅析Vue.js 中的条件渲染指令
Nov 19 Javascript
浅谈Javascript常用正则表达式应用
Mar 08 Javascript
微信小程序页面间传值与页面取值操作实例分析
Apr 30 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
星际争霸中的热键
2020/03/04 星际争霸
PHP数组的交集array_intersect(),array_intersect_assoc(),array_inter_key()函数的小问题
2011/05/29 PHP
推荐十款免费 WordPress 插件
2015/03/24 PHP
PHP函数实现从一个文本字符串中提取关键字的方法
2015/07/01 PHP
PHP中如何防止外部恶意提交调用ajax接口
2016/04/11 PHP
Yii2针对指定url的生成及图片等的引入方法小结
2016/07/18 PHP
利用PHP扩展Xhprof分析项目性能实践教程
2018/09/05 PHP
phpStudy vscode 搭建debug调试的教程详解
2020/07/28 PHP
动态改变textbox的宽高的js
2006/10/26 Javascript
jQuery 可以拖动的div实现代码 脚本之家修正版
2009/06/26 Javascript
心扬JS分页函数代码
2010/09/10 Javascript
理解JSON:3分钟课程
2011/10/28 Javascript
Json2Template.js 基于jquery的插件 绑定JavaScript对象到Html模板中
2011/10/29 Javascript
js改变img标签的src属性在IE下没反应的解决方法
2013/07/23 Javascript
Json和Jsonp理论实例代码详解
2013/11/15 Javascript
jQuery在iframe中无法弹出对话框的解决方法
2014/01/12 Javascript
关于微信中a链接无法跳转问题
2016/08/02 Javascript
浅析location.href跨窗口调用函数
2016/11/22 Javascript
Bootstrap实现提示框和弹出框效果
2017/01/11 Javascript
Vue2.0学习系列之项目上线的方法步骤(图文)
2018/09/25 Javascript
NodeJS 文件夹拷贝以及删除功能
2019/09/03 NodeJs
vue+elementUI 实现内容区域高度自适应的示例
2020/09/26 Javascript
Python tkinter模块中类继承的三种方式分析
2017/08/08 Python
Python实现查询某个目录下修改时间最新的文件示例
2018/08/29 Python
python 获取微信好友列表的方法(微信web)
2019/02/21 Python
详解python安装matplotlib库三种失败情况
2020/07/28 Python
CSS3制作圆角图片和椭圆形图片
2016/07/08 HTML / CSS
使用jTopo给Html5 Canva中绘制的元素添加鼠标事件
2014/05/15 HTML / CSS
有关HTML5中背景音乐的自动播放功能
2017/10/16 HTML / CSS
香港迪士尼乐园酒店预订:Hong Kong Disneyland Hotels
2017/05/02 全球购物
俄罗斯电子产品、计算机和家用电器购物网站:OLDI
2019/10/27 全球购物
英国儿童设计师服装和玩具购物网站:Zac & Lulu
2020/10/19 全球购物
Unix控制后台进程都有哪些进程
2016/09/22 面试题
欢迎标语大全
2014/06/21 职场文书
结婚保证书
2015/01/16 职场文书
标枪加油稿
2015/07/22 职场文书