programing

V-모델이 입력에 대한 값 변경을 수신하지 않음(vuejs)

prostudy 2022. 5. 6. 19:46
반응형

V-모델이 입력에 대한 값 변경을 수신하지 않음(vuejs)

나는 사용자 입력을 들을 수 있거나 뷰에 의해 변경될 수 있는 객체 속성을 가지고 있다.아래 스냅된 경우:

  • 만약 내가 무언가를 입력한다면 내 입력값은 업데이트되고widget.Title.Name업데이트됨.
  • "외부 업데이트" 단추를 클릭하면 해당 속성이widget.Title.Name업데이트되었지만 위의 필드의 값은 업데이트되지 않음.

예상 결과 : 편집 가능한 텍스트 값은 다음과 같이 동시에 업데이트해야 한다.widget.Title.Name변하다

업데이트되지 않은 이유를 이해할 수 없으며, vue 검사기에서 내 속성을 검사하면 모든 필드가 업데이트됨(widget.Title.Name그리고Value)은 올바르게 업데이트되었지만 html은 업데이트되지 않았다.

Vue.component('editable-text', {
		template: '#editable-text-template',
		props: {
			value: {
				type: String,
				default: '',
			},
			contenteditable: {
				type: Boolean,
				default: true,
			},
		},
		computed: {
			listeners() {
				return { ...this.$listeners, input: this.onInput };
			},
		},
		mounted() {

			this.$refs["editable-text"].innerText = this.value;
		},
		methods: {
			onInput(e) {
				this.$emit('input', e.target.innerText);
			}
		}
		});
    
    	var vm = new Vue({
		el: '#app',
		data: {
			widget: {
        Title: {
          Name: ''
        }
      }
		},
		async created() {
			this.widget.Title.Name = "toto"
		},
    methods: {
			externalChange: function () {
				this.widget.Title.Name = "changed title";
			},
    }
})
button{
  height:50px;
  width:100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <editable-text v-model="widget.Title.Name"></editable-text>
  <template>Name : {{widget.Title.Name}}</template>
  <br>
  <br>
  <button v-on:click="externalChange">External update</button>
</div>

<template id="editable-text-template">
	<p ref="editable-text" v-bind:contenteditable="contenteditable"
	   v-on="listeners">
	</p>
</template>

비슷한 이슈에 대해 많은 과목을 검색했는데 반응성에 문제가 있어서 입력에 특별한 문제가 있는 것 같아.무슨 일이 일어나고 있는지 아십니까? 이벤트를 변경하기 위해 청취자를 추가하려고 했지만 트리거되지 않음widget.Title.Name변하다

이 문제를 해결하려면 3가지 다른 일을 해야 한다.

  1. 프로펠러와 이름이 같은 시계 속성 추가(여기 값)
  2. Lodash에서 디바운스 기능을 추가하여 요청 수 제한
  3. 사용자가 입력할 때 좋은 위치에 커서(담배 위치)를 다시 가져올 수 있는 기능

세 번째 점의 경우: 값을 변경할 때widget.Title.Name구성 요소가 다시 활성화되고 캐럿 위치가 입력 시작 시 0으로 다시 초기화된다.그러니까, 마지막 위치에서 다시 업데이트해야 해. 그렇지 않으면 오른쪽에서 왼쪽으로 쓸 거야.

나는 나의 최종 해결책으로 위의 조각들을 업데이트했다.나는 이것이 다른 사람들이 여기에 오는 데 도움이 되기를 바란다.

Vue.component('editable-text', {
		template: '#editable-text-template',
		props: {
			value: {
				type: String,
				default: '',
			},
			contenteditable: {
				type: Boolean,
				default: true,
			},
		},
    //Added watch value to watch external change <-> enter here by user input or when component or vue change the watched property
    watch: {
			value: function (newVal, oldVal) { // watch it
				// _.debounce is a function provided by lodash to limit how
				// often a particularly expensive operation can be run.
				// In this case, we want to limit how often we update the dom
				// we are waiting for the user finishing typing his text
				const debouncedFunction = _.debounce(() => {
					this.UpdateDOMValue();
				}, 1000); //here your declare your function
				debouncedFunction(); //here you call it
				//not you can also add a third argument to your debounced function to wait for user to finish typing, but I don't really now how it works and I didn't used it. 
			}
		},
		computed: {
			listeners() {
				return { ...this.$listeners, input: this.onInput };
			},
		},
		mounted() {

			this.$refs["editable-text"].innerText = this.value;
		},
		methods: {
			onInput(e) {
				this.$emit('input', e.target.innerText);
			},
      UpdateDOMValue: function () {
				// Get caret position
				if (window.getSelection().rangeCount == 0) {
					//this changed is made by our request and not by the user, we
					//don't have to move the cursor
					this.$refs["editable-text"].innerText = this.value;
				} else {
					let selection = window.getSelection();
					let index = selection.getRangeAt(0).startOffset;

					//with this line all the input will be remplaced, so the cursor of the input will go to the
					//beginning... and you will write right to left....
					this.$refs["editable-text"].innerText = this.value;
					
					//so we need this line to get back the cursor at the least position
					setCaretPosition(this.$refs["editable-text"], index);

				}
				
			}
		}
		});
    
var vm = new Vue({
		el: '#app',
		data: {
			widget: {
        Title: {
          Name: ''
        }
      }
		},
		async created() {
			this.widget.Title.Name = "toto"
		},
    methods: {
			externalChange: function () {
				this.widget.Title.Name = "changed title";
			},
    }
})


	/**
	 * Set caret position in a div (cursor position)
	 * Tested in contenteditable div
	 * @@param el :  js selector to your element
	 * @@param caretPos : index : exemple 5
	 */
	function setCaretPosition(el, caretPos) {
		var range = document.createRange();
		var sel = window.getSelection();
		if (caretPos > el.childNodes[0].length) {
			range.setStart(el.childNodes[0], el.childNodes[0].length);
		}
		else
		{
			range.setStart(el.childNodes[0], caretPos);
		}		
		range.collapse(true);
		sel.removeAllRanges();
	}
button{
  height:50px;
  width:100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <editable-text v-model="widget.Title.Name"></editable-text>
  <template>Name : {{widget.Title.Name}}</template>
  <br>
  <br>
  <button v-on:click="externalChange">External update</button>
</div>

<template id="editable-text-template">
	<p ref="editable-text" v-bind:contenteditable="contenteditable"
	   v-on="listeners">
	</p>
</template>

$root를 사용할 수 있다.$children[0]

Vue.component('editable-text', {
    template: '#editable-text-template',
    props: {
        value: {
            type: String,
            default: '',
        },
        contenteditable: {
            type: Boolean,
            default: true,
        },
    },
    computed: {
        listeners() {
            return {...this.$listeners, input: this.onInput
            };
        },
    },
    mounted() {
        this.$refs["editable-text"].innerText = this.value;
    },
    methods: {
        onInput(e) {
            this.$emit('input', e.target.innerText);
        }
    }
});

var vm = new Vue({
    el: '#app',
    data: {
        widget: {
            Title: {
                Name: ''
            }
        }
    },
    async created() {
        this.widget.Title.Name = "toto"
    },
    methods: {
        externalChange: function(e) {
            this.widget.Title.Name = "changed title";
            this.$root.$children[0].$refs["editable-text"].innerText = "changed title";
        },
    }
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="app">
    <editable-text v-model="widget.Title.Name"></editable-text>
    <template>Name : {{widget.Title.Name}}</template>
    <br>
    <br>
    <button v-on:click="externalChange">External update</button>
</div>

<template id="editable-text-template">
    <p ref="editable-text" v-bind:contenteditable="contenteditable" v-on="listeners">
    </p>
</template>

또는 루트 인스턴스에 전달 소품 사용

Vue.component('editable-text', {
    template: '#editable-text-template',
    props: {
        value: {
            type: String,
            default: '',
        },
        contenteditable: {
            type: Boolean,
            default: true,
        },
    },
    computed: {
        listeners() {
            return {...this.$listeners, input: this.onInput
            };
        },
    },
    mounted() {
        this.$refs["editable-text"].innerText = this.value;
         this.$root.$on("titleUpdated",(e)=>{
     this.$refs["editable-text"].innerText = e;
  })
    },
    methods: {
        onInput(e) {
            this.$emit('input', e.target.innerText);
        }
    }
});

var vm = new Vue({
    el: '#app',
    data: {
        widget: {
            Title: {
                Name: ''
            }
        }
    },
    async created() {
        this.widget.Title.Name = "toto"
    },
    methods: {
        externalChange: function(e) {
            this.widget.Title.Name = "changed title";
            this.$root.$emit("titleUpdated", this.widget.Title.Name);
        },
    }
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="app">
    <editable-text v-model="widget.Title.Name"></editable-text>
    <template>Name : {{widget.Title.Name}}</template>
    <br>
    <br>
    <button v-on:click="externalChange">External update</button>
</div>

<template id="editable-text-template">
    <p ref="editable-text" v-bind:contenteditable="contenteditable" v-on="listeners">
    </p>
</template>

참조URL: https://stackoverflow.com/questions/57091059/v-model-is-not-listening-to-value-change-for-an-input-vuejs

반응형