この記事では、ラジオ・チェックボックスの選択することで、動的に価格が更新される見積もりフォームの作成について解説しています。
HTMLでフォームのレイアウトを作り、JavaScriptでユーザーの選択に応じて価格を算出、更新します。そして、CSSで見た目を整えます。
ちょっとコード量は多めです。
for (let i =)
JavaScriptのfor
ループは、一定の回数だけコードを繰り返し実行するために使用されます。構文はfor ([初期化]; [条件式]; [増分]) {...}
です。
例えば、配列の全要素に対して何らかの操作を行いたい場合、以下のように使用します:
let array = [1, 2, 3, 4, 5];
for (let i = 0; i < array.length; i++) {
console.log(array[i]);
}
let i =
の部分は、このループの初期化フェーズで、変数i
を定義し、初期値を設定します。通常、このi
は”iterator”(イテレータ)を意味し、ループ内でのインデックスやカウンタとして使われます。
この例では、i
が0から始まり(let i = 0
)、i
が配列の長さより小さい間(i < array.length
)、ループが実行されます。
それぞれのループの終わりで、i
は1ずつ増加します(i++
)。
計算をして合計金額を出すサンプル
それでは、早速サンプルです。
各金額が記載してアルボタンをクリックすると、上部の合計額に加算されていきます。
Total: ¥0
こんな感じでラジオボタン・チェックボックス・スライダーを動かすと金額計算されます。
実装の手順と方法
コードの詳細の前に、実装の手順と方法について解説していきます。
まずは、HTMLを記述します。
設置したい場所に記述しましょう。
<p id="total">Total: ¥0</p>
<form id="estimate-form">
<div class="estimate-formInner">
<p class="estimate-formHeading">Media Option<span>個別選択</span></p>
<input type="radio" name="media" value="0" id="media-option-0">
<label for="media-option-0"><span class="choiceOption">Media Option 0</span>¥0</label>
<input type="radio" name="media" value="1000" id="media-option-1">
<label for="media-option-1"><span class="choiceOption">Media Option 1</span>¥1000</label>
<input type="radio" name="media" value="2000" id="media-option-2">
<label for="media-option-2"><span class="choiceOption">Media Option 2</span>¥2000</label>
<input type="radio" name="media" value="3000" id="media-option-3">
<label for="media-option-3"><span class="choiceOption">Media Option 3</span>¥3000</label>
</div>
<div class="estimate-formInner">
<p class="estimate-formHeading">Site Type Option<span>個別選択</span></p>
<input type="radio" name="siteType" value="1000" id="siteType-option-1">
<label for="siteType-option-1"><span class="choiceOption">Site Type Option 1</span>¥1000</label>
<input type="radio" name="siteType" value="2000" id="siteType-option-2">
<label for="siteType-option-2"><span class="choiceOption">Site Type Option 2</span>¥2000</label>
</div>
<div class="estimate-formInner">
<p class="estimate-formHeading">Page Option</p>
<label>
Pages: <input type="range" name="pages" min="0" max="10" value="0">
</label>
</div>
<div class="estimate-formInner">
<p class="estimate-formHeading">Feature Option<span>複数選択</span></p>
<input type="checkbox" name="features" value="500" id="features-option-1">
<label for="features-option-1"><span class="choiceOption">Feature Option 1</span>¥500</label>
<input type="checkbox" name="features" value="1000" id="features-option-2">
<label for="features-option-2"><span class="choiceOption">Feature Option 2</span>¥1000</label>
<input type="checkbox" name="features" value="1500" id="features-option-3">
<label for="features-option-3"><span class="choiceOption">Feature Option 3</span>¥1500</label>
</div>
<div class="estimate-formInner">
<p class="estimate-formHeading">Additional Option<span>複数選択</span></p>
<input type="checkbox" name="options" value="800" id="additional-option-1">
<label for="additional-option-1"><span class="choiceOption">Additional Option 1</span>¥800</label>
<input type="checkbox" name="options" value="1600" id="additional-option-2">
<label for="additional-option-2"><span class="choiceOption">Additional Option 2</span>¥1600</label>
</div>
<div class="estimate-formInner">
<p class="estimate-formHeading">Design Option<span>個別選択</span></p>
<input type="radio" name="design" value="1500" id="design-option-1">
<label for="design-option-1"><span class="choiceOption">Design Option 1</span>¥1500</label>
<input type="radio" name="design" value="2500" id="design-option-2">
<label for="design-option-2"><span class="choiceOption">Design Option 2</span>¥2500</label>
<input type="radio" name="design" value="3500" id="design-option-3">
<label for="design-option-3"><span class="choiceOption">Design Option 3</span>¥3500</label>
<input type="radio" name="design" value="4500" id="design-option-4">
<label for="design-option-4"><span class="choiceOption">Design Option 4</span>¥4500</label>
</div>
</form>
次に、JavaScriptのコードを記述します。
コードは <body>〜</body>
で、</body>
の閉じタグ(クロージングタグ)の前に記述しましょう。
// IDを使ってフォーム要素を取得
const form = document.getElementById('estimate-form');
// IDを使って総価格表示要素を取得
const totalElement = document.getElementById('total');
// ユーザーの選択に基づいて総価格を計算する関数
function calculateTotal() {
// 総価格を0に初期化
let total = 0;
// 選択されたメディアオプションの値を取得
const media = document.querySelector('input[name="media"]:checked');
// メディアオプションが選択されていれば、その値を総価格に加算
if (media) total += Number(media.value);
// 選択されたサイトタイプオプションの値を取得
const siteType = document.querySelector('input[name="siteType"]:checked');
// サイトタイプオプションが選択されていれば、その値を総価格に加算
if (siteType) total += Number(siteType.value);
// ページ数を取得
const pages = document.querySelector('input[name="pages"]');
// ページ数のコストを総価格に加算(ここでは1ページあたり100円と仮定)
total += Number(pages.value) * 100;
// 選択されたすべての機能オプションの値を取得
const features = document.querySelectorAll('input[name="features"]:checked');
// 選択されたすべての機能オプションをループし、その値を総価格に加算
for (let i = 0; i < features.length; i++) {
total += Number(features[i].value);
}
// 選択されたすべての追加オプションの値を取得
const options = document.querySelectorAll('input[name="options"]:checked');
// 選択されたすべての追加オプションをループし、その値を総価格に加算
for (let i = 0; i < options.length; i++) {
total += Number(options[i].value);
}
// 選択されたデザインオプションの値を取得
const design = document.querySelector('input[name="design"]:checked');
// デザインオプションが選択されていれば、その値を総価格に加算
if (design) total += Number(design.value);
// 計算した総価格で総価格表示テキストを更新
totalElement.innerText = `Total: ¥${total}`;
}
// フォームにchangeイベントが発生した時にcalculateTotal関数を起動するイベントリスナーを追加
form.addEventListener('change', calculateTotal);
最後にCSSを書きましょう。
/* form要素に対するスタイル */
form#estimate-form {
display: flex; /* 子要素をフレックスアイテムとして配置 */
flex-direction: column; /* フレックスアイテムを列方向に配置 */
gap: 25px; /* フレックスアイテム間の隙間を25pxに設定 */
margin-top: 30px; /* 上部のマージンを30pxに設定 */
}
/* インナーコンテナに対するスタイル */
.estimate-formInner {
display: flex; /* 子要素をフレックスアイテムとして配置 */
flex-direction: row; /* フレックスアイテムを行方向に配置 */
gap: 20px 25px; /* フレックスアイテム間の隙間を20px(縦)と25px(横)に設定 */
flex-wrap: wrap; /* フレックスアイテムがコンテナの幅を超えた場合、折り返しを許可 */
border-bottom: solid 1px #eee; /* 下部に1pxの固体の境界線を追加 */
padding-bottom: 25px; /* 下部のパディングを25pxに設定 */
}
/* 最後のインナーコンテナに対するスタイル */
.estimate-formInner:last-child {
padding-bottom: 0; /* 下部のパディングを0に設定 */
border: none; /* 境界線を削除 */
}
/* ヘッダ要素に対するスタイル */
p.estimate-formHeading {
display: flex; /* 子要素をフレックスアイテムとして配置 */
width: 100%; /* 幅を100%に設定 */
margin: 0 0 -10px; /* マージンの下部を-10pxに設定 */
font-size: 1.3rem; /* フォントサイズを1.3remに設定 */
justify-content: flex-start; /* フレックスアイテムを左に寄せる */
align-items: center; /* フレックスアイテムを中央に配置 */
gap: 10px; /* フレックスアイテム間の隙間を10pxに設定 */
}
/* ヘッダ要素内のspanに対するスタイル */
p.estimate-formHeading span {
background: #999; /* 背景色を#999に設定 */
color: #fff; /* 文字色を#fff(白)に設定 */
font-size: 0.8rem; /* フォントサイズを0.8remに設定 */
padding: 2px 10px 2px; /* パディングを上下2px、左右10pxに設定 */
border-radius: 9999px; /* ボーダーの半径を非常に大きく設定して丸くする */
font-weight: 600; /* フォントの太さを600に設定 */
letter-spacing: 0.04rem; /* 文字間隔を0.04remに設定 */
}
/* ラジオボタンとチェックボックスを非表示に設定 */
.estimate-formInner input[type="radio"], .estimate-formInner input[type="checkbox"] {
display: none; /* 表示しない */
}
/* チェックが入ったラジオボタンとチェックボックスのラベルのスタイルを設定 */
.estimate-formInner input[type="radio"]:checked + label, .estimate-formInner input[type="checkbox"]:checked + label {
background: #707070; /* 背景色を#707070に設定 */
color: #fff; /* 文字色を#fff(白)に設定 */
}
/* ラベルに対するスタイル */
.estimate-formInner label {
display: flex; /* 子要素をフレックスアイテムとして配置 */
flex-direction: column; /* フレックスアイテムを列方向に配置 */
align-items: center; /* フレックスアイテムを中央に配置 */
padding: 15px 15px 5px; /* パディングを上下15px、左右5pxに設定 */
transition: 0.3s ease-in-out; /* トランジション効果を0.3秒で適用 */
box-shadow: 0 0 3px 0 rgb(0 0 0 / 12%), 0 1px 3px 0 rgb(0 0 0 / 9%); /* 影を設定 */
border-radius: 3px; /* ボーダーの半径を3pxに設定 */
cursor: pointer; /* マウスカーソルをポインターに設定 */
font-weight: 600; /* フォントの太さを600に設定 */
font-size: 1.2rem; /* フォントサイズを1.2remに設定 */
gap: 3px; /* フレックスアイテム間の隙間を3pxに設定 */
background: #fff; /* 背景色を#fff(白)に設定 */
}
/* ラベルにマウスをホバーすると影を強調、上に少し浮き上がる、透明度を0.8に、背景色を薄灰色に設定 */
.estimate-formInner label:hover {
box-shadow: 0 15px 30px -5px rgb(0 0 0 / 15%), 0 0 5px rgb(0 0 0 / 10%); /* ホバー時の影を設定 */
transform: translateY(-4px); /* ホバー時に上に4px移動 */
opacity: 0.8; /* 透明度を0.8に設定 */
background: #f5f5f5; /* 背景色を#f5f5f5に設定 */
}
これで完成です。
ざっくりとしたコードの解説
コードは、HTML・JavaScript・CSSの3種類です。ざっくりですが、順に解説していきます。
HTML
HTMLは、複数のウェブサイト構築オプションを選択し、それに基づいて総費用を算出するためのフォームを表示します。
<p id="total">Total: ¥0</p>
<form id="estimate-form">
<div class="estimate-formInner">
<p class="estimate-formHeading">Media Option<span>個別選択</span></p>
<input type="radio" name="media" value="0" id="media-option-0">
<label for="media-option-0"><span class="choiceOption">Media Option 0</span>¥0</label>
<input type="radio" name="media" value="1000" id="media-option-1">
<label for="media-option-1"><span class="choiceOption">Media Option 1</span>¥1000</label>
<input type="radio" name="media" value="2000" id="media-option-2">
<label for="media-option-2"><span class="choiceOption">Media Option 2</span>¥2000</label>
<input type="radio" name="media" value="3000" id="media-option-3">
<label for="media-option-3"><span class="choiceOption">Media Option 3</span>¥3000</label>
</div>
<div class="estimate-formInner">
<p class="estimate-formHeading">Site Type Option<span>個別選択</span></p>
<input type="radio" name="siteType" value="1000" id="siteType-option-1">
<label for="siteType-option-1"><span class="choiceOption">Site Type Option 1</span>¥1000</label>
<input type="radio" name="siteType" value="2000" id="siteType-option-2">
<label for="siteType-option-2"><span class="choiceOption">Site Type Option 2</span>¥2000</label>
</div>
<div class="estimate-formInner">
<p class="estimate-formHeading">Page Option</p>
<label>
Pages: <input type="range" name="pages" min="0" max="10" value="0">
</label>
</div>
<div class="estimate-formInner">
<p class="estimate-formHeading">Feature Option<span>複数選択</span></p>
<input type="checkbox" name="features" value="500" id="features-option-1">
<label for="features-option-1"><span class="choiceOption">Feature Option 1</span>¥500</label>
<input type="checkbox" name="features" value="1000" id="features-option-2">
<label for="features-option-2"><span class="choiceOption">Feature Option 2</span>¥1000</label>
<input type="checkbox" name="features" value="1500" id="features-option-3">
<label for="features-option-3"><span class="choiceOption">Feature Option 3</span>¥1500</label>
</div>
<div class="estimate-formInner">
<p class="estimate-formHeading">Additional Option<span>複数選択</span></p>
<input type="checkbox" name="options" value="800" id="additional-option-1">
<label for="additional-option-1"><span class="choiceOption">Additional Option 1</span>¥800</label>
<input type="checkbox" name="options" value="1600" id="additional-option-2">
<label for="additional-option-2"><span class="choiceOption">Additional Option 2</span>¥1600</label>
</div>
<div class="estimate-formInner">
<p class="estimate-formHeading">Design Option<span>個別選択</span></p>
<input type="radio" name="design" value="1500" id="design-option-1">
<label for="design-option-1"><span class="choiceOption">Design Option 1</span>¥1500</label>
<input type="radio" name="design" value="2500" id="design-option-2">
<label for="design-option-2"><span class="choiceOption">Design Option 2</span>¥2500</label>
<input type="radio" name="design" value="3500" id="design-option-3">
<label for="design-option-3"><span class="choiceOption">Design Option 3</span>¥3500</label>
<input type="radio" name="design" value="4500" id="design-option-4">
<label for="design-option-4"><span class="choiceOption">Design Option 4</span>¥4500</label>
</div>
</form>
オプションには「Media Option」「Site Type Option」「Page Option」「Feature Option」「Additional Option」「Design Option」があり、ラジオボタン、チェックボックス、スライダーで選択します。
各項目には、それぞれの価格がついています。
JavaScript
JavaScriptのコードは、ユーザーがオプションを選択するたびに、それらのオプションの総価格を計算して表示する機能です。
// IDを使ってフォーム要素を取得
const form = document.getElementById('estimate-form');
// IDを使って総価格表示要素を取得
const totalElement = document.getElementById('total');
// ユーザーの選択に基づいて総価格を計算する関数
function calculateTotal() {
// 総価格を0に初期化
let total = 0;
// 選択されたメディアオプションの値を取得
const media = document.querySelector('input[name="media"]:checked');
// メディアオプションが選択されていれば、その値を総価格に加算
if (media) total += Number(media.value);
// 選択されたサイトタイプオプションの値を取得
const siteType = document.querySelector('input[name="siteType"]:checked');
// サイトタイプオプションが選択されていれば、その値を総価格に加算
if (siteType) total += Number(siteType.value);
// ページ数を取得
const pages = document.querySelector('input[name="pages"]');
// ページ数のコストを総価格に加算(ここでは1ページあたり100円と仮定)
total += Number(pages.value) * 100;
// 選択されたすべての機能オプションの値を取得
const features = document.querySelectorAll('input[name="features"]:checked');
// 選択されたすべての機能オプションをループし、その値を総価格に加算
for (let i = 0; i < features.length; i++) {
total += Number(features[i].value);
}
// 選択されたすべての追加オプションの値を取得
const options = document.querySelectorAll('input[name="options"]:checked');
// 選択されたすべての追加オプションをループし、その値を総価格に加算
for (let i = 0; i < options.length; i++) {
total += Number(options[i].value);
}
// 選択されたデザインオプションの値を取得
const design = document.querySelector('input[name="design"]:checked');
// デザインオプションが選択されていれば、その値を総価格に加算
if (design) total += Number(design.value);
// 計算した総価格で総価格表示テキストを更新
totalElement.innerText = `Total: ¥${total}`;
}
// フォームにchangeイベントが発生した時にcalculateTotal関数を起動するイベントリスナーを追加
form.addEventListener('change', calculateTotal);
.addEventListener()
の「change」イベントは、フォームの入力要素が変更されたときに発火します。そのたびに、calculateTotal
関数が実行され、選択されたすべてのオプションの価格を合計し、その合計を表示します。
各コードの詳細はコメントアウトにも記載しているので、チェックしてみてください。
CSS
CSSは、指定されたIDやクラスを持つ要素に対して様々なスタイルを適用します。
/* form要素に対するスタイル */
form#estimate-form {
display: flex; /* 子要素をフレックスアイテムとして配置 */
flex-direction: column; /* フレックスアイテムを列方向に配置 */
gap: 25px; /* フレックスアイテム間の隙間を25pxに設定 */
margin-top: 30px; /* 上部のマージンを30pxに設定 */
}
/* インナーコンテナに対するスタイル */
.estimate-formInner {
display: flex; /* 子要素をフレックスアイテムとして配置 */
flex-direction: row; /* フレックスアイテムを行方向に配置 */
gap: 20px 25px; /* フレックスアイテム間の隙間を20px(縦)と25px(横)に設定 */
flex-wrap: wrap; /* フレックスアイテムがコンテナの幅を超えた場合、折り返しを許可 */
border-bottom: solid 1px #eee; /* 下部に1pxの固体の境界線を追加 */
padding-bottom: 25px; /* 下部のパディングを25pxに設定 */
}
/* 最後のインナーコンテナに対するスタイル */
.estimate-formInner:last-child {
padding-bottom: 0; /* 下部のパディングを0に設定 */
border: none; /* 境界線を削除 */
}
/* ヘッダ要素に対するスタイル */
p.estimate-formHeading {
display: flex; /* 子要素をフレックスアイテムとして配置 */
width: 100%; /* 幅を100%に設定 */
margin: 0 0 -10px; /* マージンの下部を-10pxに設定 */
font-size: 1.3rem; /* フォントサイズを1.3remに設定 */
justify-content: flex-start; /* フレックスアイテムを左に寄せる */
align-items: center; /* フレックスアイテムを中央に配置 */
gap: 10px; /* フレックスアイテム間の隙間を10pxに設定 */
}
/* ヘッダ要素内のspanに対するスタイル */
p.estimate-formHeading span {
background: #999; /* 背景色を#999に設定 */
color: #fff; /* 文字色を#fff(白)に設定 */
font-size: 0.8rem; /* フォントサイズを0.8remに設定 */
padding: 2px 10px 2px; /* パディングを上下2px、左右10pxに設定 */
border-radius: 9999px; /* ボーダーの半径を非常に大きく設定して丸くする */
font-weight: 600; /* フォントの太さを600に設定 */
letter-spacing: 0.04rem; /* 文字間隔を0.04remに設定 */
}
/* ラジオボタンとチェックボックスを非表示に設定 */
.estimate-formInner input[type="radio"], .estimate-formInner input[type="checkbox"] {
display: none; /* 表示しない */
}
/* チェックが入ったラジオボタンとチェックボックスのラベルのスタイルを設定 */
.estimate-formInner input[type="radio"]:checked + label, .estimate-formInner input[type="checkbox"]:checked + label {
background: #707070; /* 背景色を#707070に設定 */
color: #fff; /* 文字色を#fff(白)に設定 */
}
/* ラベルに対するスタイル */
.estimate-formInner label {
display: flex; /* 子要素をフレックスアイテムとして配置 */
flex-direction: column; /* フレックスアイテムを列方向に配置 */
align-items: center; /* フレックスアイテムを中央に配置 */
padding: 15px 15px 5px; /* パディングを上下15px、左右5pxに設定 */
transition: 0.3s ease-in-out; /* トランジション効果を0.3秒で適用 */
box-shadow: 0 0 3px 0 rgb(0 0 0 / 12%), 0 1px 3px 0 rgb(0 0 0 / 9%); /* 影を設定 */
border-radius: 3px; /* ボーダーの半径を3pxに設定 */
cursor: pointer; /* マウスカーソルをポインターに設定 */
font-weight: 600; /* フォントの太さを600に設定 */
font-size: 1.2rem; /* フォントサイズを1.2remに設定 */
gap: 3px; /* フレックスアイテム間の隙間を3pxに設定 */
background: #fff; /* 背景色を#fff(白)に設定 */
}
/* ラベルにマウスをホバーすると影を強調、上に少し浮き上がる、透明度を0.8に、背景色を薄灰色に設定 */
.estimate-formInner label:hover {
box-shadow: 0 15px 30px -5px rgb(0 0 0 / 15%), 0 0 5px rgb(0 0 0 / 10%); /* ホバー時の影を設定 */
transform: translateY(-4px); /* ホバー時に上に4px移動 */
opacity: 0.8; /* 透明度を0.8に設定 */
background: #f5f5f5; /* 背景色を#f5f5f5に設定 */
}
主にレイアウトや外観に関するプロパティを使用しています。コメントは各プロパティがどのように働いているかを説明しています。
さいごに
今回は、JavaScriptで金額計算をするフォームの作り方についての解説でした。
また、このコードに加えて、downloadボタンを設置してjsPDFというライブラリを使って完成した金額や明細をPDFを生成することも可能です。
是非あわせてチェックしてみてください。