programing

Vue.js에서 v-model을 사용하기 위한 사용자 지정 양식 컨트롤을 쓰는 중

goodsources 2022. 8. 9. 22:59
반응형

Vue.js에서 v-model을 사용하기 위한 사용자 지정 양식 컨트롤을 쓰는 중

여러 폼 입력을 하나의 커스텀 컴포넌트로 패키지화하는 방법을 배우기 위해 Vue.js에서 커스텀컨트롤을 작성하려고 합니다.

프로젝트 셋업은 다음과 같습니다(표준 webpack-simple vue cli 셋업).

$ tree -L 1
.
├── README.md
├── index.html
├── node_modules
├── package.json
├── src
└── webpack.config.js

다음은 최상위 Vue 인스턴스 .vue 파일입니다.

// App.vue
<template>
    <div class="container">
        <form v-if="!submitted" >
            <div class="row">
                <div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
                    <form>
                        <fullname v-model="user.fullName"></fullname>

                        <div class="form-group">
                            <label for="email">Email:</label>
                            <input id="email" type="email" class="form-control" v-model="user.email">
                            <label for="password">Password:</label>
                            <input id="password" type="password" class="form-control" v-model="user.password">
                        </div>

                        <fieldset class="form-group">
                            <legend>Store data?</legend>
                            <div class="form-check">
                              <label class="form-check-label">
                                <input type="radio" class="form-check-input" name="storeDataRadios" id="storeDataRadios1" value="true" checked v-model="user.storeData">
                                Store Data
                              </label>
                            </div>
                            <div class="form-check">
                            <label class="form-check-label">
                                <input type="radio" class="form-check-input" name="storeDataRadios" id="storeDataRadios2" value="false" v-model="user.storeData">
                                No, do not make my data easily accessible
                              </label>
                            </div>
                        </fieldset>
                    </form>

                    <button class="btn btn-primary" @click.prevent="submitForm()">Submit</button>

                </div>
            </div>
        </form>
        <hr>
        <div v-if="submitted" class="row">
            <div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h4>Your Data</h4>
                    </div>
                    <div class="panel-body">
                        <p>Full Name: {{ user.fullName }}</p>
                        <p>Mail: {{ user.email }}</p>
                        <p>Password: {{ user.password }} </p>
                        <p>Store in Database?: {{ user.storeData }}</p>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    import FullName from './FullName.vue';

    export default {
        data() {
            return {
                user: {
                    fullName: 'John Smith',
                    email: '', 
                    password: '',
                    storeData: true,
                }, 
                submitted: false
            }
        }, 
        methods: {
            submitForm() {
                this.submitted = true;
            },
        },
        components: {
            'fullname' : FullName,
        }
    }
</script>

<style>
</style>

커스텀 컴포넌트 파일은 다음과 같습니다.

<template>
    <div class="form-group">
        <label for="firstName">First name:</label>
        <input id="firstName" type="text" class="form-control" :value="first" @input="emitChange(true, $event)">

        <label for="lastName">Last name:</label>
        <input id="lastName" type="text" class="form-control" :value="last" @input="emitChange(false, $event)">
    </div>
</template>

<script>
    export default {
        props: ['value'],
        methods: {
            emitChange(isFirst, evt) {
                let name = '';
                let evtValue = evt.target.value == undefined ? "" : evt.target.value;

                if (isFirst) {
                    name = evtValue +" "+ this.second;
                } else {
                    name = this.first +" "+ evtValue;
                }

                this.value = name;
                this.$emit('input', this.value);
            }
        },
        computed: {
            first() {
                if (this.value != "")
                    return this.value.split(" ")[0];
                else return "";
            }, 
            last() {
                if (this.value != "")
                    return this.value.split(" ")[1];
                else return "";
            }
        }
    }
</script>

또한 다음과 같이 프로포트의 값을 직접 편집하고 있기 때문에 제가 실수를 하고 있다는 것도 깨달았습니다.

this.value = name;

(오류가 아니라 Vue.JS에 경고가 표시됩니다).

단, 그 이전이라도 첫 번째 입력 상자에 입력하면 두 번째 입력 상자의 값이 다음과 같이 업데이트됩니다.undefined(...와트!?)

커스텀 폼 제어 컴포넌트를 올바르게 설정하는 방법에 대해 조언해 주시면 감사하겠습니다.또, 이 예가 기능하지 않는 이유.

내 생각에 여기서 문제는 이름이 어디서 끝나고 성이 어디서 시작되는지 모른다는 거야.버락 후세인 오바마를 예로 들자면, 그가 벨기에 사람이라고 상상해보세요. 그의 이름은 버락 후세인 반 오바마입니다.어느 부분이 먼저고 어느 부분이 성인지 추측할 수 없습니다.

그러나 이름이 정확히 한 단어이고 나머지 이름이 성이라고 말할 수 있는 경우 구현 예를 다음에 제시하겠습니다(아래로 줄 바꿈).문제를 설명하기 위해 Obamas second name을 입력해 봅니다.

그렇지 않으면 구성 요소가 양방향 바인딩 구성 요소처럼 작동합니다.전체 이름 구성 요소의 개별 값을 변경하거나 루트 구성 요소의 전체 이름을 편집하여 모든 항목을 최신 상태로 유지할 수 있습니다.워처는 위에서 변경 내용을 수신하고 업데이트 방법을 통해 변경 내용이 백업됩니다.

Vue.component('fullname', {
  template: '#fullname',
  data() {
    // Keep the separate names on the component
    return {
      firstname: this.value.split(' ')[0],
      lastname: this.value.split(' ')[1],
    }
  },
  props: ['value'],
  methods: {
    update() {
      // Notify the parent of a change, chain together the name
      // and emit
      this.$emit('input', `${this.firstname} ${this.lastname}`);
    },
  },
  mounted() {
    // Parse the prop input and take the first word as firstname,
    // the rest as lastname.
    // The watcher ensures that the component stays up to date
    // if the parent changes.
    this.$watch('value', function (value){
      var splitted = value.split(' ');
      this.firstname = splitted[0];
      splitted.shift();
      this.lastname = splitted.join(' ');
    });
  }
});

new Vue({
  el: '#app',
  data: {
    fullname: 'Barack Obama',
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>

<div id="app">
  <fullname v-model="fullname"></fullname>
  <p>Thanks, {{fullname}}</p>
  <input v-model="fullname" />
</div>

<template id="fullname">
  <div>
    <input v-model="firstname" @input="update" type="text" id="firstname" />
    <input v-model="lastname" @input="update" type="text" id="lastname" />
  </div>
</template>

언급URL : https://stackoverflow.com/questions/43568635/writing-custom-form-controls-to-use-v-model-in-vue-js

반응형