• vue组件--TagsInput


    简介

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

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

    • 注:以下代码需要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>
    
    
  • 相关阅读:
    npm设置和取消代理的方法 规格严格
    Postgresql数据库的一些字符串操作函数 规格严格
    cpio命令 规格严格
    SNMP_1.3.6.1.6.3.1.1.5.5 authenticationFailure 规格严格
    【23】种设计模式全面解析(超级详细) 规格严格
    利用ssh反向代理以及autossh实现从外网连接内网服务器 规格严格
    PostgreSQL常用字符串函数与操作符 规格严格
    ssh端口转发实现外网访问 规格严格
    Kafka解析之topic创建 规格严格
    mysql union 与 union all 语法及用法 规格严格
  • 原文地址:https://www.cnblogs.com/small-coder/p/9139304.html
Copyright © 2020-2023  润新知