Javascript 编写自定义表单控件以在Vue.js中使用v-model

Javascript 编写自定义表单控件以在Vue.js中使用v-model,javascript,vue.js,vuejs2,Javascript,Vue.js,Vuejs2,我正试图写一篇文章来学习如何将多个表单输入打包到一个定制组件中 我的项目设置如下所示(标准网页包简单vue cli设置): 以下是我的顶级Vue实例.Vue文件: // App.vue <template> <div class="container"> <form v-if="!submitted" > <div class="row"> <div class=

我正试图写一篇文章来学习如何将多个表单输入打包到一个定制组件中

我的项目设置如下所示(标准网页包简单vue cli设置):

以下是我的顶级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>
(不是错误,但Vue.JS会给出警告)

但是,即使在此之前,在第一个输入框中键入内容也会导致第二个输入框将其值更新为
未定义(…wat!?)


如果您能就如何正确设置自定义表单控件组件提供建议,我们将不胜感激!(以及为什么这个例子不起作用)。

我认为,这里的问题是你永远不知道名字从哪里结束,姓氏从哪里开始。以巴拉克·侯赛因·奥巴马(Barack Hussein Obama)为例,假设他是比利时人,他的名字应该是巴拉克·侯赛因·范·奥巴马(Barack Hussein van Obama)。您无法安全地假定哪个部分是第一个,哪个部分是姓氏

但是,如果您可以说firstname正好是一个单词,其余的是lastname,那么下面是一个示例实现(精简)。为了说明这个问题,试着用奥巴马的第二个名字

否则,该组件的行为类似于双向绑定组件。您可以更改fullname组件上的单独值,或者编辑根组件上的fullname,所有内容都保持最新。观察者监听来自上面的更改,更新方法发出更改备份

Vue.component('fullname'{
模板:“#全名”,
数据(){
//在组件上保留单独的名称
返回{
名字:this.value.split(“”)[0],
lastname:this.value.split(“”)[1],
}
},
道具:['value'],
方法:{
更新(){
//通知父级更改,将名称链接在一起
//发出
this.$emit('input',`${this.firstname}${this.lastname}`);
},
},
安装的(){
//解析prop输入并将第一个单词作为firstname,
//其余的都是姓。
//观察者确保组件保持最新状态
//如果父项发生更改。
此.$watch('value',函数(value){
var splitted=值。split(“”);
this.firstname=splitted[0];
splitted.shift();
this.lastname=splitted.join(“”);
});
}
});
新Vue({
el:“#应用程序”,
数据:{
全名:“巴拉克·奥巴马”,
}
});

谢谢,{{fullname}


太棒了,现在一切都有意义了!!
// 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;