Vue:限制文本区域输入中的字符,截断过滤器?

新手上路,请多包涵

<textarea name="" id="" cols="30" rows="10" v-model="$store.state.user.giftMessage | truncate 150"></textarea> 我尝试创建一个自定义过滤器:

 filters: {
    truncate(text, stop, clamp) {
        return text.slice(0, stop) + (stop < text.length ? clamp || '...' : '')
    }
}

但是当我把它放在 v-model 上作为输入时,这并没有破坏构建……

有什么建议吗?

原文由 J W 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 462
2 个回答

这是您真正想要使用组件的情况之一。

这是 一个示例组件,它呈现 textarea 并限制文本数量。

请注意:这不是生产就绪的,请处理所有角落案例组件。它旨在作为示例。

 Vue.component("limited-textarea", {
  props:{
    value:{ type: String, default: ""},
    max:{type: Number, default: 250}
  },
  template: `
    <textarea v-model="internalValue" @keydown="onKeyDown"></textarea>
  `,
  computed:{
    internalValue: {
      get() {return this.value},
      set(v){ this.$emit("input", v)}
    }
  },
  methods:{
    onKeyDown(evt){
      if (this.value.length >= this.max) {
        if (evt.keyCode >= 48 && evt.keyCode <= 90) {
          evt.preventDefault()
          return
        }
      }
    }
  }
})

该组件实现 v-model 并且仅在文本长度小于指定的最大值时才对数据发出更改。它通过侦听 keydown 并在文本长度等于或大于允许的最大值时阻止默认操作(键入字符)来做到这一点。

 console.clear()

Vue.component("limited-textarea", {
  props:{
    value:{ type: String, default: ""},
    max:{type: Number, default: 250}
  },
  template: `
    <textarea v-model="internalValue" @keydown="onKeyDown"></textarea>
  `,
  computed:{
    internalValue: {
      get() {return this.value},
      set(v){ this.$emit("input", v)}
    }
  },
  methods:{
    onKeyDown(evt){
      if (this.value.length >= this.max) {
        if (evt.keyCode >= 48 && evt.keyCode <= 90) {
          evt.preventDefault()
          return
        }
      }
    }
  }
})

new Vue({
  el: "#app",
  data:{
    text: ""
  }
})
 <script src="https://unpkg.com/vue@2.4.2"></script>
<div id="app">
  <limited-textarea v-model="text"
                    :max="10"
                    cols="30"
                    rows="10">
  </limited-textarea>
</div>

问题中代码的另一个问题是 Vuex 不允许您直接设置状态值;你必须通过突变来做到这一点。也就是说,应该有一个接受新值并设置它的 Vuex 突变,并且代码应该提交突变。

 mutations: {
  setGiftMessage(state, message) {
    state.user.giftMessage = message
  }
}

在你的 Vue 中:

 computed:{
  giftMessage:{
    get(){return this.$store.state.user.giftMessage},
    set(v) {this.$store.commit("setGiftMessage", v)}
  }
}

从技术上讲,代码应该使用 getter 来获取用户(它是giftMessage),但这应该可以。在您将使用的模板中:

 <limited-textarea cols="30" rows="10" v-model="giftMessage"></limited-textarea>

这是一个使用 Vuex 的完整示例。

 console.clear()

const store = new Vuex.Store({
  state:{
    user:{
      giftMessage: "test"
    }
  },
  getters:{
    giftMessage(state){
      return state.user.giftMessage
    }
  },
  mutations:{
    setGiftMessage(state, message){
      state.user.giftMessage = message
    }
  }
})

Vue.component("limited-textarea", {
  props:{
    value:{ type: String, default: ""},
    max:{type: Number, default: 250}
  },
  template: `
    <textarea v-model="internalValue" @keydown="onKeyDown"></textarea>
  `,
  computed:{
    internalValue: {
      get() {return this.value},
      set(v){ this.$emit("input", v)}
    }
  },
  methods:{
    onKeyDown(evt){
      if (this.value.length >= this.max) {
        if (evt.keyCode >= 48 && evt.keyCode <= 90) {
          evt.preventDefault()
          return
        }
      }
    }
  }
})

new Vue({
  el: "#app",
  store,
  computed:{
    giftMessage:{
      get(){ return this.$store.getters.giftMessage},
      set(v){ this.$store.commit("setGiftMessage", v)}
    }
  }
})
 <script src="https://unpkg.com/vue@2.4.2"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/2.4.0/vuex.js"></script>
<div id="app">
  <limited-textarea v-model="giftMessage"
                    :max="10"
                    cols="30"
                    rows="10">
  </limited-textarea>
  Message: {{giftMessage}}
</div>

原文由 Bert 发布,翻译遵循 CC BY-SA 4.0 许可协议

抱歉闯入。正在寻找解决方案。看着他们所有人。对我来说,它们看起来太复杂了。我一直在寻找简单。因此,我喜欢@Даниил Пронин 的回答。但它有@J。兰博指出了潜在的问题。

尽可能接近原生 html 文本元素。我想出的解决方案是:

Vue 模板

<textarea v-model="value" @input="assertMaxChars()">

JavaScript

 let app = new Vue({
  el: '#app',
  data: {
    value: 'Vue is working!',
    maxLengthInCars: 25
  },

  methods: {
    assertMaxChars: function () {
        if (this.value.length >= this.maxLengthInCars) {
            this.value = this.value.substring(0,this.maxLengthInCars);
        }
    }
  }
})

这是一个 REPL 链接: https ://repl.it/@tsboh/LimitedCharsInTextarea

我看到的好处是:

  • 元素尽可能接近原生元素
  • 简单的代码
  • textarea 保持焦点
  • 删除仍然有效
  • 也适用于粘贴文本

无论如何快乐编码

原文由 Alphons 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题