vue 컴포넌트에 다른 입력을 입력할 때 입력 파일 값이 누락되는 이유는 무엇입니까?
2개의 컴포넌트가 있습니다.
첫 번째 컴포넌트(부모 컴포넌트)는 다음과 같습니다.
<template>
<div>
...
<form-input id="name" name="name" v-model="name">Name</form-input>
<form-input id="birth-date" name="birth_date" type="date" v-model="birthDate">Date of Birth</form-input>
<form-input id="avatar" name="avatar" type="file" v-on:triggerChange="onFileChange($event)">Avatar</form-input>
<form-input id="mobile-number" name="mobile_number" type="number" v-model="mobileNumber">Mobile Number</form-input>
...
</div>
</template>
<script>
export default {
data() {
return {
name: null,
birthDate: null,
mobileNumber: null
}
},
methods: {
onFileChange(e) {
let self = this
this.validate(e.target.files[0])
.then(function(res) {
let files = e.target.files,
reader = new FileReader()
// if any values
if (files.length) {
self.removeErrorMessageUpload()
self.files = files[0]
reader.onload = (e) => {
self.updateProfileAvatar(e.target.result)
}
reader.readAsDataURL(files[0])
}
})
.catch(function() {
// do something in the case where the image is not valid
self.displayErrorMessageUpload()
})
},
validate(image) {
let self = this
return new Promise(function(resolve, reject) {
// validation file type
if (!self.allowableTypes.includes(image.name.split(".").pop().toLowerCase())) {
reject()
}
// validation file size
if (image.size > self.maximumSize) {
reject()
}
// validation image resolution
let img = new Image()
img.src = window.URL.createObjectURL(image)
img.onload = function() {
let width = img.naturalWidth,
height = img.naturalHeight
window.URL.revokeObjectURL(img.src)
if (width != 100 && height != 100) {
reject()
}
else {
resolve()
}
}
})
},
}
}
</script>
상위 구성 요소에서 하위 구성 요소(폼 입력 구성 요소)를 호출합니다.
자녀 구성요소는 입력 유형 텍스트, 입력 유형 날짜, 입력 유형 파일 및 입력 유형 번호입니다.나는 그것들을 모두 하나의 컴포넌트로 결합한다.
자구성요소는 다음과 같습니다.
<template>
<div class="form-group">
<label :for="id" class="col-sm-3 control-label"><slot></slot></label>
<div class="col-sm-9">
<input :type="type" :name="name" :id="id" class="form-control" :value="value" v-on:change="applySelected($event)" @input="$emit('input', $event.target.value)">
</div>
</div>
</template>
<script>
export default {
name: "form-input",
props: {
'id': String,
'name': String,
'isRequired': {
type: Boolean,
default: true
},
'type': {
type: String,
default() {
if(this.type == 'number')
return 'number'
return 'text'
}
},
'value': {
type: [String, Number]
}
},
methods: {
applySelected(e) {
this.$emit('triggerChange', e)
}
}
}
</script>
1개의 컴포넌트로 결합하기 때문에 새로운 문제가 발생합니다.
입력 유형 파일을 입력하면 파일 값이 입력 유형 파일에 표시됩니다.
그러나 입력 유형 텍스트에 입력하면 입력 유형 파일의 값이 누락됩니다.
입력 형식 파일의 값이 누락된 이유는 무엇입니까?
데모:
Vue.component('form-input', {
template: "#form-input-tpl",
name: "form-input",
props: {
'id': String,
'name': String,
'isRequired': {type: Boolean, default: true},
'type': { type: String, default () {if (this.type == 'number') {return 'number'} else {return 'text'}}},
'value': { type: [String, Number] }
},
methods: {
applySelected(e) { this.$emit('triggerChange', e) }
}
});
new Vue({
el: '#app',
data: {
name: null,
birthDate: null,
mobileNumber: null
},
methods: {
onFileChange(e) {
// ...
}
}
})
<script src="https://unpkg.com/vue"></script>
<template id="form-input-tpl">
<div class="form-group">
<label :for="id" class="col-sm-3 control-label"><slot></slot></label>
<div class="col-sm-9">
<input :type="type" :name="name" :id="id" class="form-control" :value="value" v-on:change="applySelected($event)" @input="$emit('input', $event.target.value)">
</div>
</div>
</template>
<div id="app">
<h3>Select a file, then type a name. The file will be reset.</h3>
<div>
<form-input id="name" name="name" v-model="name">Name</form-input>
<form-input id="birth-date" name="birth_date" type="date" v-model="birthDate">Date of Birth</form-input>
<form-input id="avatar" name="avatar" type="file" v-on:triggerChange="onFileChange($event)">Avatar</form-input>
<form-input id="mobile-number" name="mobile_number" type="number" v-model="mobileNumber">Mobile Number</form-input>
</div>
</div>
문제는 다음과 같습니다.
에서 파일을 선택한 후
<form-input type="file">
, 에 무언가를 입력했을 경우<form-input type="type">
,그<form-input type="file">
소거합니다.왜 그런 것일까요?
이 문제가 발생하는 이유는 편집 시<form-input type="text">
Vue는 컴포넌트를 "보수"합니다.
그리고 그것이 후회할 때<form-input type="file">
새로운 버전이기 때문에 "Nothing selected"로 돌아갑니다.<input type="file">
.
솔루션:파일 값 유지
Kaiido가 코멘트에서 지적한 바와 같이 최신 버전의 브라우저에서는 파일 설정을 할 수 있습니다.<input type="file">
표준적인 방법으로
아래 코드는 이렇게 동작합니다.감시하고 있습니다.value
속성(부모가 를 사용하는 경우)v-model
그 값을 로 설정합니다..files
의 특성<input type="file">
.
우리는 두 개를 사용해야 한다.<input>
(와 함께)v-if
/v-else
)왜냐하면,<input type="file">
,그:value
속성을 설정할 수 있습니다.이벤트 핸들러는 달라야 합니다( )@change="$emit('input', $event.target.files)"
) 、 ) ) 、 、ref
이 경우,files
.
아래 전체 작업 데모입니다.
Vue.component('form-input', {
template: "#form-input-tpl",
name: "form-input",
props: {
'id': String,
'name': String,
'isRequired': {type: Boolean, default: true},
'type': {type: String, default: 'text'},
'value': {type: [String, Number, FileList, DataTransfer]}
},
mounted() {
// set files upon creation or update if parent's value changes
this.$watch('value', () => {
if (this.type === "file") { this.$refs.inputFile.files = this.value; }
}, { immediate: true });
}
});
new Vue({
el: '#app',
data: {
name: null,
birthDate: null,
mobileNumber: null,
files: null
}
})
<script src="https://unpkg.com/vue"></script>
<template id="form-input-tpl">
<div class="form-group">
<label :for="id" class="col-sm-3 control-label"><slot></slot></label>
<div class="col-sm-9">
<input v-if="type !== 'file'" :type="type" :name="name" :id="id" class="form-control" :value="value" @input="$emit('input', $event.target.value)">
<input v-else :type="type" :name="name" :id="id" class="form-control" @change="$emit('input', $event.target.files)" ref="inputFile">
</div>
</div>
</template>
<div id="app">
<div>
<form-input id="name" name="name" v-model="name">Name</form-input>
<form-input id="birth-date" name="birth_date" type="date" v-model="birthDate">Date of Birth</form-input>
<form-input id="avatar" name="avatar" type="file" v-model="files">Avatar</form-input>
<form-input id="mobile-number" name="mobile_number" type="number" v-model="mobileNumber">Mobile Number</form-input>
</div>
</div>
를 사용하여file-change
이벤트 및validate
기능:
Vue.component('form-input', {
template: "#form-input-tpl",
name: "form-input",
props: {
'id': String,
'name': String,
'isRequired': {type: Boolean, default: true},
'type': {type: String, default: 'text'},
'value': {type: [String, Number, FileList, DataTransfer]}
},
mounted() {
// set files upon creation or update if parent's value changes
this.$watch('value', () => {
if (this.type === "file") { this.$refs.inputFile.files = this.value; }
}, { immediate: true });
}
});
new Vue({
el: '#app',
data: {
name: null,
birthDate: null,
mobileNumber: null,
filesVModel: null,
allowableTypes: ['jpg', 'jpeg', 'png'],
maximumSize: 1000,
files: null
},
methods: {
onFileChange(e) {
console.log('onfilechange!');
let self = this
this.validate(e.target.files[0])
.then(function(res) {
let files = e.target.files,
reader = new FileReader()
// if any values
if (files.length) {
self.removeErrorMessageUpload()
self.files = files[0]
reader.onload = (e) => {
self.updateProfileAvatar(e.target.result)
}
reader.readAsDataURL(files[0])
}
})
.catch(function(err) {
// do something in the case where the image is not valid
self.displayErrorMessageUpload(err)
})
},
validate(image) {
let self = this
return new Promise(function(resolve, reject) {
// validation file type
if (!self.allowableTypes.includes(image.name.split(".").pop().toLowerCase())) {
reject("Type " + image.name.split(".").pop().toLowerCase() + " is not allowed.")
}
// validation file size
if (image.size > self.maximumSize) {
reject("Image size " + image.size + " is larger than allowed " + self.maximumSize + ".")
}
// validation image resolution
let img = new Image()
img.src = window.URL.createObjectURL(image)
img.onload = function() {
let width = img.naturalWidth,
height = img.naturalHeight
window.URL.revokeObjectURL(img.src)
if (width != 100 && height != 100) {
reject("Width and height are " + width + " and " + height + " and not both 100")
} else {
resolve()
}
}
})
},
displayErrorMessageUpload(msg) {
console.log('displayErrorMessageUpload', msg);
},
removeErrorMessageUpload() {
console.log('removeErrorMessageUpload');
},
updateProfileAvatar(result) {
console.log('updateProfileAvatar', result);
}
}
})
<script src="https://unpkg.com/vue"></script>
<template id="form-input-tpl">
<div class="form-group">
<label :for="id" class="col-sm-3 control-label"><slot></slot></label>
<div class="col-sm-9">
<input v-if="type !== 'file'" :type="type" :name="name" :id="id" class="form-control" :value="value" @input="$emit('input', $event.target.value)">
<input v-else :type="type" :name="name" :id="id" class="form-control" @change="$emit('input', $event.target.files)" ref="inputFile" v-on:change="$emit('file-change', $event)">
</div>
</div>
</template>
<div id="app">
<div>
<form-input id="name" name="name" v-model="name">Name</form-input>
<form-input id="birth-date" name="birth_date" type="date" v-model="birthDate">Date of Birth</form-input>
<form-input id="avatar" name="avatar" type="file" v-model="filesVModel" @file-change="onFileChange">Avatar</form-input>
<form-input id="mobile-number" name="mobile_number" type="number" v-model="mobileNumber">Mobile Number</form-input>
</div>
</div>
언급URL : https://stackoverflow.com/questions/49337786/why-the-value-of-input-file-missing-when-i-input-the-another-input-on-the-vue-co
'programing' 카테고리의 다른 글
루트가 변경되면 이전 컴포넌트의 모든 http 요청을 취소합니다. (0) | 2022.08.08 |
---|---|
롬복에서 세터/게터 1개 누락 (0) | 2022.08.08 |
어떻게 SparseArray을 반복하는 데? (0) | 2022.08.08 |
Android에서 모바일 장치의 위도와 경도를 얻는 방법 (0) | 2022.08.08 |
vuex 작업 Vue.js에서 개체 어레이를 정렬할 수 없습니다. (0) | 2022.08.07 |