JSFiddle - React, Tailwind, and code Playground
by ken3desu
HTML
<script src="//code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<link rel="stylesheet" href="//stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script>
<script src="//stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>
<div id="app">
<form-input
label="ユーザ名"
id="edit_username"
name="username"
placeholder="例:浜松 太郎"></form-input>
<form-input
label="メールアドレス"
id="edit_mail"
name="mail"
type="mail"
validation-template="mail"></form-input>
<form-input
label="番号"
id="edit_number"
name="number"
type="number"
value="0.53"
max="1"
min="0"
step="0.01"></form-input>
<form-input
label="色"
id="edit_color"
name="color"
type="color"
value="#F000FF"
></form-input>
</div>
<template id="form-input-template">
<div class="row">
<div class="col-md-12">
<div class="form-group row">
<label
:for="id"
class="col-md-3 col-form-label text-md-right">
{{ label }}
</label>
<div class="col-md-9">
<input
:id="id"
:class="type === 'color' ? 'input-color' : null"
:name="name"
:type="type"
:placeholder="placeholder"
:value="value"
:max="max"
:min="min"
:step="step"
v-model="vModelValue"
class="form-control"
@input="validation()">
<div
v-show="isValidationErr"
class="text-black-50">{{ localValidationErrMsg }}</div>
</div>
</div>
</div>
</div>
</template>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
.input-color {
height: 2.5em;
}
JavaScript
Vue.component('form-input', {
props: {
label: {type: String, required: true},
id: {type: String, required: true},
name: {type: String, required: true},
type: {type: String, default: 'text'},
placeholder: {type: String, default: null},
value: {type: String, default: null},
max: {type: String|Number, default: null},
min: {type: String|Number, default: null},
step: {type: String|Number, default: null},
validationErrMsg: {type: String, default: 'バリデーションエラー'},
validationExcludePattern: {type: String, default: null},
validationTemplate: {type: String, default: null},
},
data() {
return {
vModelValue: null,
isValidationErr: false,
localValidationExcludePattern: null,
localValidationErrMsg: null,
};
},
created() {
switch (this.validationTemplate) {
case 'mail':
this.localValidationExcludePattern = /[^\w"!#$%&'*+\-/=?^`{|}~. ()<>[\]:;@,]/g;
this.localValidationErrMsg = `半角英数字と次の記号のみが入力できます。"!#$%&'*+-/=?^\`{|}~. ()<>[]:;@,`;
break;
case 'tel':
this.localValidationExcludePattern = /[^\-\d]/g;
this.localValidationErrMsg = `半角数字と-のみが入力できます。`;
break;
default:
this.localValidationExcludePattern = this.validationExcludePattern;
this.localValidationErrMsg = this.validationErrMsg;
}
},
methods: {
/**
* バリデーションチェック。エラーが起きるとエラーメッセージを出して自動訂正
*/
validation() {
if (this.localValidationExcludePattern == null || this.vModelValue == null) {
return;
}
if (this.vModelValue.length > this.vModelValue.replace(this.localValidationExcludePattern, '').length) {
this.vModelValue = this.vModelValue.replace(this.localValidationExcludePattern, '');
this.isValidationErr = true;
} else {
this.isValidationErr = false;
}
},
},
template: '#form-input-template',
});
const vm = new Vue({
el: '#app',
});