Javascript-форум (https://javascript.ru/forum/)
-   Библиотеки/Тулкиты/Фреймворки (https://javascript.ru/forum/library-toolkit-framework/)
-   -   Vue JS странность (https://javascript.ru/forum/library-toolkit-framework/77687-vue-js-strannost.html)

dpts 07.06.2019 10:26

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);
}

То все срабатывает как надо, с первого раза.
Но так уж вышло, что мне эта проверка нужна именно там.

Может быть может кто-то объяснить почему так, где собака порылась и как исправить, чтобы с первого раза срабатывало?

Ким чен ин 16.06.2019 00:00

вообще так нельзя делать
computed для этого " this.v = this.v.substr(0,this.max);"
не предназначен, в итоге результат не правильный
вот так должно быть
computed:{
		valid: function(){
			return this.pattern.test(this.v);
		}
	},

dpts 16.06.2019 04:41

Цитата:

Сообщение от Ким чен ин (Сообщение 509077)
вообще так нельзя делать...

А почему так нельзя делать?
Дело-то скорее всего не в том, что обрезка завернута в 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>

С тем же результатом - проверкой срабатывающей через раз.

Ким чен ин 16.06.2019 11:44

потому что 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);
			}
}

dpts 16.06.2019 15:50

Цитата:

Сообщение от Ким чен ин (Сообщение 509081)
потому что computed это не функция, это свойство, хоть и с возможностью вычисления но все таки свойство. А свойство не может изменять сторонние переменные. Это не предусмотрено парадигмой vue. Если написать такое например в пхп шторме, он покажет ошибку, хотя и не критическую, но укажет что это косяк. Но в данно случае да, проблема не в этом.

С противоречием парадигме VUE понял избавимся от противоречия.
Перепишем обработчики в предыдущем варианте (когда компонент с инпутом) по предложенной вами схеме:
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);
		}
    }
}

Имеем то же самое, подрезка срабатывает каждый раз при попытке дописать цифр.
Проверка срабатывает через раз.

Ким чен ин 16.06.2019 16:37

тогда я думаю надо просто посмотреть, что каждый раз приходит сюда
console.log(this.res.value)
this.res.valid = this.pattern.test(this.res.value);

сразу ясно будет что к чему

dpts 16.06.2019 16:53

Цитата:

Сообщение от Ким чен ин (Сообщение 509089)
тогда я думаю надо просто посмотреть, что каждый раз приходит сюда
console.log(this.res.value)
this.res.valid = this.pattern.test(this.res.value);

сразу ясно будет что к чему

В том и дело, что в this.res.value всегда все в порядке.
А this.res.valid по кругу true - false - true - false true - false.....

Такое ощущение что this.res.valid = this.pattern.test(this.res.value); срабатывает раньше подрезки.

Ким чен ин 16.06.2019 18:04

не может быть, это синхронный код.
Единственный вариант тогда this.pattern.test(this.res.value);
не правильно работает

Aetae 16.06.2019 22:34

С точки зрения парадигмы всё сказали.
А теперь с технической точки зрения: computed не вычисляется каждый раз. В vue хитрая система кэширования. Если vue считает, что ничего не поменялось - оно вернёт последнее значение.
Также все свойства в data на самом деле (для реактивности) заменяются на геттеры с сеттерами, а потому this.v = 'что-то' - это не прямое назначение, а вызов vue логики. Соответственно может что-то поломаться и на этом этапе от неправильного подхода.

Короче, вместо хаков делайте по человечески и будет вам счастье.)

dpts 17.06.2019 09:05

Цитата:

Сообщение от Aetae (Сообщение 509099)
С точки зрения парадигмы всё сказали.
А теперь с технической точки зрения: 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, время: 12:34.