Vue JS странность
Приветствую. Может кто-нибудь подскажет где собака порылась.
Имеем допустим функцию:
function test(str){
console.log(str);
var pattern = /^\+\d{11}$/g;
if (str.length > 12){
str=str.substr(0,12);
}
console.log(str);
console.log(pattern.test(str));
return pattern.test(str);
}
если ей скормить +12345678901 или +123456789011 она вернет true Пытаюсь завернуть ее в VUE.JS:
var vm = new Vue({
el: '#app',
data () {
v:'+12345678901',
max: 12,
pattern: /^\+\d{11}$/g
},
computed:{
valid: function(){
if (this.v.length > this.max){
this.v = this.v.substr(0,this.max);
}
return this.pattern.test(this.v);
}
},
watch:{
v: function(){
if (this.v.length > this.max){
this.v = this.v.substr(0,this.max);
}
}
}
});
если в VUE dev tools меняю v на +123456789011, последняя единица отрезается, что логично, но valid стает false. Тут-же еще раз меняю v на +123456789011, последняя единица отрезается и valid стает true. и так по кругу. То-есть при заворачивании функции в vue регекспов .test() начинает срабатывать через раз. При этом, если из функции, формирующей valid убрать проверку на количество символов
if (this.v.length > this.max){
this.v = this.v.substr(0,this.max);
}
То все срабатывает как надо, с первого раза. Но так уж вышло, что мне эта проверка нужна именно там. Может быть может кто-то объяснить почему так, где собака порылась и как исправить, чтобы с первого раза срабатывало? |
вообще так нельзя делать
computed для этого " this.v = this.v.substr(0,this.max);" не предназначен, в итоге результат не правильный вот так должно быть
computed:{
valid: function(){
return this.pattern.test(this.v);
}
},
|
Цитата:
Дело-то скорее всего не в том, что обрезка завернута в computed потому что, можно например так:
<script type="text/javascript">
Vue.component('vt-input', {
data: function () {
return {
pattern: /^\+\d{11}$/g,
max:12,
res:{
valid:Boolean,
value:String
}
}
},
mounted:function(){
this.res.value = this.value.value;
},
props: {
value:{
type:Object
}
},
template: `
<div>
<input
v-model="res.value"
v-on:input="$emit(\'input\', vtReturn($event.target.value))">
</div>
`,
methods:{
vtReturn:function(str){
if (str.length > this.max){
this.res.value = str.substr(0,this.max);
}
this.res.valid = this.pattern.test(this.res.value);
return this.res;
}
}
});
</script>
</head>
<body>
<div id="app">
<vt-input v-model="inputVal"></vt-input>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data () {
return {
inputVal:{
valid:Boolean,
value:'+12345678901'
}
}
}
});
</script>
</body>
С тем же результатом - проверкой срабатывающей через раз. |
потому что computed это не функция, это свойство, хоть и с возможностью вычисления но все таки свойство. А свойство не может изменять сторонние переменные. Это не предусмотрено парадигмой vue. Если написать такое например в пхп шторме, он покажет ошибку, хотя и не критическую, но укажет что это косяк. Но в данно случае да, проблема не в этом.
Думаю вот так будет правильно работать (ватч не нужен)
computed:{
valid: function(){
check();
return this.pattern.test(this.v);
}
},
methods:{
check(){
if (this.v.length > this.max){
this.v = this.v.substr(0,this.max);
}
}
|
Цитата:
Перепишем обработчики в предыдущем варианте (когда компонент с инпутом) по предложенной вами схеме:
methods:{
vtReturn:function(str){
this.checker(str);
this.res.valid = this.pattern.test(this.res.value);
return this.res;
},
checker:function(str){
if (str.length > this.max){
this.res.value = str.substr(0,this.max);
}
}
}
Имеем то же самое, подрезка срабатывает каждый раз при попытке дописать цифр. Проверка срабатывает через раз. |
тогда я думаю надо просто посмотреть, что каждый раз приходит сюда
console.log(this.res.value) this.res.valid = this.pattern.test(this.res.value); сразу ясно будет что к чему |
Цитата:
А this.res.valid по кругу true - false - true - false true - false..... Такое ощущение что this.res.valid = this.pattern.test(this.res.value); срабатывает раньше подрезки. |
не может быть, это синхронный код.
Единственный вариант тогда this.pattern.test(this.res.value); не правильно работает |
С точки зрения парадигмы всё сказали.
А теперь с технической точки зрения: computed не вычисляется каждый раз. В vue хитрая система кэширования. Если vue считает, что ничего не поменялось - оно вернёт последнее значение. Также все свойства в data на самом деле (для реактивности) заменяются на геттеры с сеттерами, а потому this.v = 'что-то' - это не прямое назначение, а вызов vue логики. Соответственно может что-то поломаться и на этом этапе от неправильного подхода. Короче, вместо хаков делайте по человечески и будет вам счастье.) |
Цитата:
Отойдем немного от логики VUE и перепишем метод vtReturn из примера с компонентом:
vtReturn:function(str){
var res={
valid:Boolean,
value:''
};
if (str.length > this.max){
str = str.substr(0,this.max);
}
res.valid = this.pattern.test(str);
res.value = str;
this.res = res;
return res;
}
Теперь он в принципе не берет ничего из data для изменения, только пишет туда уже измененное. С тем же результатом как и раньше. Я же спрашиваю и прошу пояснений не от того, что я сверхмастер JS, а совсем наоборот. |
dpts, прости, что не вникал.
На самом деле ты наступил на знатные грабли совсем в другой стороне:
/^\+\d{11}$/g
->
/^\+\d{11}$/
Если регулярка с глобальным модификатором, то она запоминает позицию предыдущего вхождения. А test, как и exec учитывает это.)
<script>
var pattern = /a/g;
document.write( pattern.lastIndex, ' ' , pattern.test('a a a '), '<br>');
document.write( pattern.lastIndex, ' ' , pattern.test('a a a '), '<br>');
document.write( pattern.lastIndex, ' ' , pattern.test('a a a '), '<br>');
document.write( pattern.lastIndex, ' ' , pattern.test('a a a '), '<br>');
document.write( pattern.lastIndex, ' ' , pattern.test('a a a '), '<br>...');
document.close();
</script>
P.S. А правильно форматировать свойства в vue имеет смысл через сеттеры, условно так:
computed:{
v: {
get: function(){
return this.innerV;
},
set: function(v){
this.innerV = v.length > this.max ? v.substr(0,this.max) : v;
}
}
}
|
Благодарю. Запомню про "фичу" регекспов
Цитата:
Лень было пример нормальный писать. Хотел, как короче. |
| Часовой пояс GMT +3, время: 01:09. |