<template>
<input
@input="formatValue"
type="text"
:value="formattedValue"
/>
</template>
<script type="text/javascript">
import {formatPhoneNumber} from '~/utils/string';
export default {
computed: {
formattedValue: function(){
return formatPhoneNumber(this.value)
},
},
methods: {
formatValue(e) {
this.$emit('input', formatPhoneNumber(e.target.value))
}
},
props: ['value']
}
</script>
只要formatPhoneNumber(value)
产生不同的值,一切都会正常,但是一旦达到最大长度(自formatPhoneNumber('xx xx xx xx xx whatever') == 'xx xx xx xx xx'
起),发出的值与当前存储的值相同。
这是完全可以的,除了结果不会导致状态突变和组件未重新呈现之外,因此不会调用formattedValue()
。
所以我最终在商店中得到xx xx xx xx xx
,但是由于本地输入值与商店中的值不同,因此输入显示xx xx xx xx xx whatever
。
如何避免这种意外行为?将formatPhoneNumber()
移至商店并不能解决我的问题,因为它仍然可以防止突变,而仅在formatPhoneNumber()
中使用formattedValue()
会使我最终在商店中得到未格式化的值也不是我想要的。
具有动态input
集的Vue的value
仍然如何管理本地状态?
答案 0 :(得分:3)
要实现所需的目标(我认为),可以将formatValue方法更改为
formatValue(e) {
this.$emit('input', e.target.value = formatPhoneNumber(e.target.value));
}
因此它将输入设置为格式化的电话号码值。一种或另一种方式是,您将覆盖输入产生的结果,因此您也可以在输入事件中执行该操作。
答案 1 :(得分:2)
我将使用v-model而不是v值,因为那样可以完全控制我要在输入字段中显示的内容。
通过这种方式,您可以设置输入值的格式,然后将其设置回模型中。看起来像这样:
<template>
<input @input="formatValue" type="text" v-model="inputModel">
</template>
<script type="text/javascript">
export default {
data() {
return {
inputModel: this.value
};
},
methods: {
formatValue() {
this.inputModel = formatPhoneNumber(this.inputModel);
this.$emit("input", this.inputModel);
}
},
props: ["value"]
};
</script>
这是我创建的working example进行测试。
答案 2 :(得分:0)
我认为最简单的方法是对父项的@input事件进行简单的单行修改,从而在更新prop值之前将其清除。
您仍然只需要发出一个值,但是在使用发出的值之前,请清除道具。
我在下面提供了一个摘录(但请注意摘录中的其他区别):
我没有指定输入字段值,而是选择使用v-model将其绑定到具有get和set方法的计算属性。这使我在访问和修改数据时可以使用不同的逻辑(在许多情况下非常方便)。
通过分离此逻辑,我能够将功能从输入事件内部移至set方法,并完全消除了输入事件。
new Vue({
el: "#app",
// props: ['valueProp'],
data: {
valueProp: "" //simulate prop data
},
computed: {
// --Value input element is binded to--
inputValue:{
get(){ //when getting the value, return the prop
return this.valueProp;
},
set(val){ //when the value is set, emit value
this.formatValue(val);
}
}
},
methods: {
// --Emit the value to the parent--
formatValue(val) {
this.parentFunction(this.formatPhoneNumber(val)); //simulate emitting the value
// this.$emit('input', formatPhoneNumber(val));
},
// --Simulate parent receiving emit event--
parentFunction(emittedValue){
console.log("emitted:" + emittedValue);
this.valueProp = null; //first clear it (updates the input field)
this.valueProp = emittedValue; //then assign it the emitted value
},
// --Simulate your format method--
// THIS LOGIC CAN BE IGNORED. It is just a quick implementation of a naive formatter.
// The "important" thing is it limits the length, to demonstrate exceeding the limit doesn't get reflected in the input field
formatPhoneNumber(val){
var phoneSpaces = [2,4,6,8]; //specify space formatting (space locations)
var maxLength = 10; //specify the max length
val = val.replace(/ /g,''); //remove existing formatting
if(val.length > maxLength) //limits the length to the max length
val = val.substring(0, maxLength);
// for the number of desired spaces, check each space location (working backwards) ... if value is longer than space location and space location is not a space ... add a space at the location.
for(var i = phoneSpaces.length-1; i >= 0; i--){
if(val.length > phoneSpaces[i] && val[phoneSpaces[i]] != " "){
val = val.substring(0, phoneSpaces[i]) + " " + val.substring(phoneSpaces[i], val.length);
}
}
return val
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model="inputValue"/>
<label style="float: right;">
Prop Value: <span>{{valueProp}}</span>
</label>
<br>
<label >format (xx xx xx xx xx)</label>
</div>