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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM