Vue:限制文本区域输入中的字符,截断过滤器?
Vue : Limit characters in text area input, truncate filter?
<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 模型上时,这并没有破坏构建...
有什么建议吗?
这是您真正想要使用组件的情况之一。
这里是一个示例组件,它呈现 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>
我使用了您的代码并将其分解为 .Vue 组件,谢谢!
<template>
<textarea v-model="internalValue" @keydown="onKeyDown"></textarea>
</template>
`
export default {
props:{
value:{ type: String, default: ""},
max:{type: Number, default: 250}
},
computed:{
internalValue: {
get() {return this.value},
set(v){ this.$emit("input", v)}
}
},
methods:{
onKeyDown(evt){
if (this.value.length >= this.max) {
evt.preventDefault();
console.log('keydown');
return
}
}
}
}
最好的方法是使用 watch 来控制字符串长度,如果字符串比您想要的长,则设置旧值:
watch: {
'inputModel': function(val, oldVal) {
if (val.length > 250) {
this.inputModel = oldVal
}
},
},
虽然我同意所选答案。您还可以使用 keydown 事件处理程序轻松防止长度。
Vue 模板
<input type="text" @keydown="limit( $event, 'myModel', 3)" v-model="myModel" />
JavaScript
export default {
name: 'SomeComponent',
data () {
return {
myModel: ''
};
},
methods: {
limit( event, dataProp, limit ) {
if ( this[dataProp].length >= limit ) {
event.preventDefault();
}
}
}
}
这样做,您还可以使用正则表达式来事件阻止接受的键类型。例如,如果您只想接受数值,您可以执行以下操作。
methods: {
numeric( event, dataProp, limit ) {
if ( !/[0-9]/.test( event.key ) ) {
event.preventDefault();
}
}
}
我改进了@J Ws 的回答。生成的代码不必定义如何对哪个按键做出反应,这就是为什么它可以与接受的答案相反的任何字符一起使用。它只关心结果的字符串长度。它还可以处理复制粘贴操作并将过长的粘贴剪切到大小:
Vue.component("limitedTextarea", {
props: {
value: {
type: String,
default: ""
},
max: {
type: Number,
default: 25
}
},
computed: {
internalValue: {
get: function () {
return this.value;
},
set: function (aModifiedValue) {
this.$emit("input", aModifiedValue.substring(0, this.max));
}
}
},
template: '<textarea v-model="internalValue" @keydown="$forceUpdate()" @paste="$forceUpdate()"></textarea>'
});
神奇之处在于@keydown 和@paste-events,它们会强制更新。由于该值已被正确切割,因此它确保 internalValue 正在相应地运行。
如果您还想保护该值免受未经检查的脚本更改,您可以添加以下观察器:
watch: {
value: function(aOldValue){
if(this.value.length > this.max){
this.$emit("input", this.value.substring(0, this.max));
}
}
}
我刚刚发现这个简单的解决方案有一个问题:如果您将光标设置在中间某处并键入,超出最大值,最后一个字符将被删除,光标将设置到文本的末尾。所以还有一定的提升空间...
我的自定义指令版本。使用简单。
<textarea v-model="input.textarea" v-max-length="10"></textarea>
Vue.directive('maxlength',{
bind: function(el, binding, vnode) {
el.dataset.maxLength = Number(binding.value);
var handler = function(e) {
if (e.target.value.length > el.dataset.maxLength) {
e.target.value = e.target.value.substring(0, el.dataset.maxLength);
var event = new Event('input', {
'bubbles': true,
'cancelable': true
});
this.dispatchEvent(event);
return;
}
};
el.addEventListener('input', handler);
},
update: function(el, binding, vnode) {
el.dataset.maxLength = Number(binding.value);
}
})
- Event() 存在浏览器兼容性问题。
- 对我来说不幸的是,keydown 方法似乎不适用于 CJK。
- 可能会有副作用,因为此方法会双倍触发输入事件。
抱歉打扰了。正在寻找解决方案。看着他们所有人。
对我来说,它们看起来太复杂了。我一直在寻找简单性。
因此,我喜欢@Даниил Пронин 的回答。但它有@J。 Rambo 指出了潜在的问题。
尽可能接近原生 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 link:https://repl.it/@tsboh/LimitedCharsInTextarea
我看到的好处是:
- 元素尽可能接近原生元素
- 简单代码
- textarea 保持焦点
- 删除仍然有效
- 也适用于粘贴文本
无论如何
快乐编码
只需像这样使用 maxlength
属性:
<textarea v-model="value" maxlength="50" />
<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 模型上时,这并没有破坏构建...
有什么建议吗?
这是您真正想要使用组件的情况之一。
这里是一个示例组件,它呈现 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>
我使用了您的代码并将其分解为 .Vue 组件,谢谢!
<template>
<textarea v-model="internalValue" @keydown="onKeyDown"></textarea>
</template>
`
export default {
props:{
value:{ type: String, default: ""},
max:{type: Number, default: 250}
},
computed:{
internalValue: {
get() {return this.value},
set(v){ this.$emit("input", v)}
}
},
methods:{
onKeyDown(evt){
if (this.value.length >= this.max) {
evt.preventDefault();
console.log('keydown');
return
}
}
}
}
最好的方法是使用 watch 来控制字符串长度,如果字符串比您想要的长,则设置旧值:
watch: {
'inputModel': function(val, oldVal) {
if (val.length > 250) {
this.inputModel = oldVal
}
},
},
虽然我同意所选答案。您还可以使用 keydown 事件处理程序轻松防止长度。
Vue 模板
<input type="text" @keydown="limit( $event, 'myModel', 3)" v-model="myModel" />
JavaScript
export default {
name: 'SomeComponent',
data () {
return {
myModel: ''
};
},
methods: {
limit( event, dataProp, limit ) {
if ( this[dataProp].length >= limit ) {
event.preventDefault();
}
}
}
}
这样做,您还可以使用正则表达式来事件阻止接受的键类型。例如,如果您只想接受数值,您可以执行以下操作。
methods: {
numeric( event, dataProp, limit ) {
if ( !/[0-9]/.test( event.key ) ) {
event.preventDefault();
}
}
}
我改进了@J Ws 的回答。生成的代码不必定义如何对哪个按键做出反应,这就是为什么它可以与接受的答案相反的任何字符一起使用。它只关心结果的字符串长度。它还可以处理复制粘贴操作并将过长的粘贴剪切到大小:
Vue.component("limitedTextarea", {
props: {
value: {
type: String,
default: ""
},
max: {
type: Number,
default: 25
}
},
computed: {
internalValue: {
get: function () {
return this.value;
},
set: function (aModifiedValue) {
this.$emit("input", aModifiedValue.substring(0, this.max));
}
}
},
template: '<textarea v-model="internalValue" @keydown="$forceUpdate()" @paste="$forceUpdate()"></textarea>'
});
神奇之处在于@keydown 和@paste-events,它们会强制更新。由于该值已被正确切割,因此它确保 internalValue 正在相应地运行。
如果您还想保护该值免受未经检查的脚本更改,您可以添加以下观察器:
watch: {
value: function(aOldValue){
if(this.value.length > this.max){
this.$emit("input", this.value.substring(0, this.max));
}
}
}
我刚刚发现这个简单的解决方案有一个问题:如果您将光标设置在中间某处并键入,超出最大值,最后一个字符将被删除,光标将设置到文本的末尾。所以还有一定的提升空间...
我的自定义指令版本。使用简单。
<textarea v-model="input.textarea" v-max-length="10"></textarea>
Vue.directive('maxlength',{
bind: function(el, binding, vnode) {
el.dataset.maxLength = Number(binding.value);
var handler = function(e) {
if (e.target.value.length > el.dataset.maxLength) {
e.target.value = e.target.value.substring(0, el.dataset.maxLength);
var event = new Event('input', {
'bubbles': true,
'cancelable': true
});
this.dispatchEvent(event);
return;
}
};
el.addEventListener('input', handler);
},
update: function(el, binding, vnode) {
el.dataset.maxLength = Number(binding.value);
}
})
- Event() 存在浏览器兼容性问题。
- 对我来说不幸的是,keydown 方法似乎不适用于 CJK。
- 可能会有副作用,因为此方法会双倍触发输入事件。
抱歉打扰了。正在寻找解决方案。看着他们所有人。 对我来说,它们看起来太复杂了。我一直在寻找简单性。 因此,我喜欢@Даниил Пронин 的回答。但它有@J。 Rambo 指出了潜在的问题。
尽可能接近原生 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 link:https://repl.it/@tsboh/LimitedCharsInTextarea
我看到的好处是:
- 元素尽可能接近原生元素
- 简单代码
- textarea 保持焦点
- 删除仍然有效
- 也适用于粘贴文本
无论如何 快乐编码
只需像这样使用 maxlength
属性:
<textarea v-model="value" maxlength="50" />