input/select/textarea各要素の状態を一時的にsessionStorageに保持し、ブラウザをリロードしたり別ページから戻って再表示した時に保持しておいた状態を各要素へ反映させ状態回復するものです。
####スクリプト####
'use strict';
{
const
// 保持対象要素CSSセレクター
cssSelectors = {
// checked系
checked : [
'input[type=checkbox]',
'input[type=radio]',
].join(),
// value系
value : [
'input[type=text]',
'input[type=password]',
'input[type=datetime-local]',
'input[type=date]',
'input[type=time]',
'input[type=month]',
'input[type=week]',
'input[type=number]',
'input[type=email]',
'input[type=range]',
'input[type=search]',
'input[type=tel]',
'input[type=url]',
'textarea',
// type属性を持たないinput要素(text扱い)
'input:not([type])',
].join(),
// selected系
selected: 'select',
},
elements = {},
storage = {
key : location.pathname + ':inputElementRetention',
};
window.addEventListener('DOMContentLoaded', function() {
if(checkStorage(storage.key + '_c') !== true) return;
storage.data = sessionStorage.getItem(storage.key);
storage.data = storage.data !== null ? JSON.parse(storage.data) : {};
// 対象要素取得・イベントリスナー追加・storageデータを各要素へ反映
// checked系
elements.checked = document.querySelectorAll(cssSelectors.checked);
for(let i = 0; i < elements.checked.length; i++) {
const e = elements.checked[i];
e.addEventListener('change', storageSet);
if(storage.data.checked !== undefined) e.checked = storage.data.checked[i];
}
// value系
elements.value = document.querySelectorAll(cssSelectors.value);
for(let i = 0; i < elements.value.length; i++) {
const e = elements.value[i];
e.addEventListener('input', storageSet);
if(storage.data.value !== undefined) e.value = storage.data.value[i];
}
// selected系
elements.selected = document.querySelectorAll(cssSelectors.selected);
for(let i = 0; i < elements.selected.length; i++) {
const e = elements.selected[i];
e.addEventListener('change', storageSet);
if(storage.data.selected !== undefined) {
for(let l = 0; l < storage.data.selected[i].length; l++) {
e.options[l].selected = storage.data.selected[i][l];
}
}
}
});
// 各要素の状態取得・storageに保持
function storageSet() {
// checked系
storage.data.checked = [];
for(let i = 0; i < elements.checked.length; i++) {
const e = elements.checked[i];
storage.data.checked[i] = e.checked ? 1 : 0;
}
// value系
storage.data.value = [];
for(let i = 0; i < elements.value.length; i++) {
const e = elements.value[i];
storage.data.value[i] = e.value;
}
// selected系
storage.data.selected = [];
for(let i = 0; i < elements.selected.length; i++) {
const e = elements.selected[i];
const selectedArray = [];
for(let l = 0; l < e.options.length; l++) {
selectedArray.push(e.options[l].selected ? 1 : 0);
}
storage.data.selected[i] = selectedArray;
}
sessionStorage.setItem(storage.key, JSON.stringify(storage.data));
}
function checkStorage(str) {
try{
sessionStorage.setItem(str, str);
sessionStorage.removeItem(str);
return true;
}
catch(e) {
return false;
}
}
}
####使用法####
保存したい要素のあるHTMLに
<script src='input_retention.js'></script>
を追記します。
ページロード時に対象要素をすべて拾って動作を適用しますので、それ以外の設定はありません。
簡易的な処理なので、対象外にしたい要素の個別指定などはありませんが、例えばtype=passwordは保持したくない、というような場合は
value : [
'input[type=text]',
'input[type=password]',
'input[type=datetime-local]',
から'input[type=password]',
を削除、という形で対応できるかと思います。
また、別スクリプトで動的に要素が増減するようなページでは、動的に増えた要素にはイベントリスナーがかかっていなかったり、保持しているデータと要素の配置が変化したりするので想定通りの動作は期待できないかと思います。
####使用例####
<!DOCTYPE html>
<html lang='ja'>
<head>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<meta charset='utf-8'>
<title>input系要素 sessionStorage保持サンプル</title>
<script src='input_retention.js'></script>
<style>
textarea {
width: 300px;
height: 100px;
}
</style>
</head>
<body>
checkbox<br>
<input type='checkbox'>
<input type='checkbox'>
<input type='checkbox'>
<input type='checkbox'>
<input type='checkbox'>
<br>
radio(nameなし)<br>
<input type='radio'>
<input type='radio'>
<input type='radio'>
<br>
radio(nameあり)<br>
<input type='radio' name='a'>
<input type='radio' name='a'>
<input type='radio' name='a'>
<br>
text<br>
<input type='text'>
<input type='text'>
<br>
password<br>
<input type='password'>
<br>
日時系<br>
<input type='datetime-local'>
<input type='date'>
<input type='time'>
<br>
<input type='month'>
<input type='week'>
<br>
number<br>
<input type='number'><br>
email<br>
<input type='email'><br>
range<br>
<input type='range'><br>
search<br>
<input type='search'><br>
tel<br>
<input type='tel'><br>
url<br>
<input type='url'><br>
type無し(text扱い)<br>
<input><br>
select(single)<br>
<select>
<option value='0'>------</option>
<option value='1'>aaaaaa</option>
<option value='2'>bbbbbb</option>
<option value='3'>cccccc</option>
</select>
<br>
select(multiple)<br>
<select multiple>
<option value='0'>AAAAAA</option>
<option value='1'>BBBBBB</option>
<option value='2'>CCCCCC</option>
<option value='3'>DDDDDD</option>
</select>
<br>
textarea<br>
<textarea></textarea><br>
<textarea></textarea>
</body>
</html>
sessionStorageですので、保持されたデータはブラウザを閉じた時点で消えます。
同一ページを別タブで開いた場合は別データ扱いになります。
どんな形式で保持しているかは、Chromeの場合であればデベロッパーツール(F12キー等で開きます)のApplication > Storage > Session Storage > 該当オリジン から確認してみてください。
location.pathname + ':inputElementRetention'
のキーのものが該当データです。
location.pathnameをキー名に含めているのは、複数ページで使用した場合にページ単位でストレージデータを使い分けられるようにするためです。