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, а совсем наоборот. |
Часовой пояс GMT +3, время: 23:48. |