반응형
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가지 다른 일을 해야 한다.
- 프로펠러와 이름이 같은 시계 속성 추가(여기 값)
- Lodash에서 디바운스 기능을 추가하여 요청 수 제한
- 사용자가 입력할 때 좋은 위치에 커서(담배 위치)를 다시 가져올 수 있는 기능
세 번째 점의 경우: 값을 변경할 때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>
반응형
'programing' 카테고리의 다른 글
타이페프의 용도는 무엇인가? (0) | 2022.05.07 |
---|---|
소수점 자리 n개로 부동 소수점 형식 지정 (0) | 2022.05.06 |
비동기 jdbc 호출이 가능한가? (0) | 2022.05.06 |
Axios를 사용하여 객체를 JSon으로 게시 (0) | 2022.05.06 |
Java에서 목록을 배열로 변환 (0) | 2022.05.06 |