コードだけをみたい人は最後に全体を載せてますのでそちらへ。
それでは本題の前に、
まずは普通にhtmlでselect要素1つ、input-text要素1つを設置します。
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>text and select form</title>
</head>
<body>
<select>
<option value="2021">2021</option>
<option value="2022">2022</option>
<option value="2023">2023</option>
</select>年
<br><br>
<input type="text">
</body>
</html>
上のHTMLをブラウザで見るとselect要素とinput-text要素が表示されます。
これらを多用して「入力ページ」を作るのはいいのですが、
そのページを印刷してそのまま利用するわけにはいきません。
フォームを使ったページを印刷すると、
行がズレる、フォント・大きさ・ベースラインが合わない、見た目のイメージが変わる、
といったことが起こるからです。
HTMLの入力フォームは印刷してみるとWYSIWYGじゃないんです。
そこで、
「入力フォームを使ったHTMLページをJavaScriptでスッキリした見た目にする」
ということを考えました。
目指すのは、
文字列クリック → 入力フォームが出現 → フォーム入力終了 → フォーム消滅 → 文字列に戻る
です。
まずは、HTMLを書き換えます。
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>text and select form</title>
</head>
<body>
<!--spanで囲みます-->
<span>2021</span>年
<br><br>
<!--spanで囲みます-->
<!--text入力変更前の文を適当に-->
<span>textを書き換えます</span>
</body>
</html>
上のHTMLをブラウザで見ると「2021年」「textを書き換えます」がそれぞれ文字列で現れています。
次に、Javascriptで扱えるようにspanタグに「id」と「onclick」イベントハンドラを配置します。
「onclick」で起動する関数は後ほど配置します。
<html>
<head>
<meta charset="UTF-8">
<title>text and select form</title>
</head>
<body>
<!--「id」と「onclick」を配置します-->
<span id="year" onclick="">2021</span>年
<br><br>
<!--「id」と「onclick」を配置します-->
<span id="line" onclick="">textを書き換えます</span>
</body>
</html>
次に、Javascriptの本体を書き込むscriptタグを、今回はわかりやすいようにspanタグの直下にそれぞれ配置します。
<html>
<head>
<meta charset="UTF-8">
<title>text and select form</title>
</head>
<body>
<span id="year" onclick="">2021</span>年
<!--scriptタグを配置します-->
<script>
</script>
<br><br>
<span id="line" onclick="">textを書き換えます</span>
<!--scriptタグを配置します-->
<script>
</script>
</body>
</html>
続いて、最初のscriptタグにspan id="year"用のJavaScriptを書きます。
<span id="year" onclick="">2021</span>年
<script>
let spanYearTag=document.getElementById("year");
let optionsArray=[2021,2022,2023];//select要素のoptionsの配列です
/*span id="year"のonclickで起動する関数です*/
function toSelect(){
let keepNen=Number(spanYearTag.innerHTML); //span id="year"の内容を(一応数値化して)変数に格納
/*select要素を構築します*/
let selectElement='<select id="year-select" onchange="fromSelect()">';//idとonchangeを書きます
for(let i=0; i<optionsArray.length; i++){//optionsArray配列からselect要素のoptionsを書きます
selectElement+='<option value="'+optionsArray[i]+'">'+optionsArray[i]+'</option>';
}
selectElement+='</select>';
/*span id="year"にselect要素を配置します*/
spanYearTag.innerHTML=selectElement;//ここでselect要素が実体化します
/*表示されていた「年」と同じoptionsをselectedにします*/
for(let i=0; i<optionsArray.length; i++){//
if(keepNen==optionsArray[i]){
document.getElementById("year-select").options[i].selected=true;
break;
}
}
/*span id="year"のonclickハンドラを無効にします*/
spanYearTag.onclick=null;//spanタグ内にselectタグあるので、selectタグへのクリックが上位spanタグに影響しないようにするためです
}
/*select id="year-select"のonchangeで起動する関数です*/
function fromSelect(){//
let selectTag=document.getElementById("year-select");
let selectNen=selectTag.value;//selectで選択されたvalueを格納
/*span id="year"に選択された年を配置します*/
spanYearTag.innerHTML=selectNen;//ここでselect要素と選択された「年」が入れ替わります
/*span id="year"にonclickを新たに配置します*/
spanYearTag.onclick=new Function("toSelect()");//nullにしたものを復活です
}
</script>
上記のJavaSciptのtoSelect関数をspan id="year"のonclickに配置します。
<html>
<head>
<meta charset="UTF-8">
<title>text and select form</title>
</head>
<body>
<!--toSelect関数をspan id="year"のonclickに設置します-->
<span id="year" onclick="toSelect()">2021</span>年
<script>
/*--略--*/
</script>
<br><br>
<span id="line" onclick="">textを書き換えます</span>
<script>
</script>
</body>
</html>
次に、二つ目のscriptタグにspan id="line"用のJavaScriptを書きます。
<script>
let spanInputTag=document.getElementById("line");
/*span id="line"のonclickで起動する関数です*/
function toText(){
let keepLine=spanInputTag.innerHTML; //span id="line"の内容を変数に格納。
/*text要素を構築します*/
let textElement='<input type="text" id="line-text" value="'+keepLine+'" onblur="fromText()">';//idとonchangeを書きます valueに変更前の文字列を設定します
/*span id="line"にtext要素を配置します*/
spanInputTag.innerHTML=textElement;//ここでtext要素が実体化します
/*text要素にフォーカスします*/
document.getElementById("line-text").focus();
document.getElementById("line-text").select();
/*span id="line"のonclickハンドラを無効にします*/
spanInputTag.onclick=null;//spanタグ内にselectタグあるので、selectタグへのクリックが上位spanタグに影響しないようにするためです
}
/*input text id="line-text"のonblurで起動する関数です*/
function fromText(){//
let textTag=document.getElementById("line-text");
let getLine=textTag.value;//textで入力されたvalueを格納
/*span id="line"に入力された文字列を配置します*/
spanInputTag.innerHTML=getLine;//ここでtext要素と入力された文字列が入れ替わります
/*span id="line"にonclickを新たに配置します*/
spanInputTag.onclick=new Function("toText()");//nullにしたものを復活させます
}
</script>
上記のJavaSciptのtoText()関数をspan id="line"のonclickに設置します。
<html>
<head>
<meta charset="UTF-8">
<title>text and select form</title>
</head>
<body>
<span id="year" onclick="toSelect()">2021</span>年
<script>
/*--略--*/
</script>
<br><br>
<!--toText関数をspan id="line"のonclickに設置します-->
<span id="line" onclick="toText()">textを書き換えます</span>
<script>
/*--略--*/
</script>
</body>
</html>
HTMLとJavaScript全体です。
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>text and select form</title>
</head>
<body>
<span id="year" onclick="toSelect()">2021</span>年
<script>
let spanYearTag=document.getElementById("year");
let optionsArray=[2021,2022,2023];//select要素のoptionsの配列です
/*span id="year"のonclickで起動する関数です*/
function toSelect(){
let keepNen=Number(spanYearTag.innerHTML); //span id="year"の内容を(一応数値化して)変数に格納
/*select要素を構築します*/
let selectElement='<select id="year-select" onchange="fromSelect()">';//idとonchangeを書きます
for(let i=0; i<optionsArray.length; i++){//optionsArray配列からselect要素のoptionsを書きます
selectElement+='<option value="'+optionsArray[i]+'">'+optionsArray[i]+'</option>';
}
selectElement+='</select>';
/*span id="year"にselect要素を配置します*/
spanYearTag.innerHTML=selectElement;//ここでselect要素が出現します
/*表示されていた「年」と同じoptionsをselectedにします*/
for(let i=0; i<optionsArray.length; i++){//
if(keepNen==optionsArray[i]){
document.getElementById("year-select").options[i].selected=true;
break;
}
}
/*span id="year"のonclickハンドラを無効にします*/
spanYearTag.onclick=null;//spanタグ内にselectタグがあるので、selectタグへのクリックが上位のspanタグに影響しないようにしています
}
/*select id="year-select"のonchangeで起動する関数です*/
function fromSelect(){//
let selectTag=document.getElementById("year-select");
let selectNen=selectTag.value;//selectで選択されたvalueを変数に格納
/*span id="year"に選択された年を配置します*/
spanYearTag.innerHTML=selectNen;//ここでselect要素と選択された「年」が入れ替わります
/*span id="year"にonclickを新たに配置します*/
spanYearTag.onclick=new Function("toSelect()");//nullにしたものを復活です
}
</script>
<br><br>
<span id="line" onclick="toText()">textを書き換えます</span>
<script>
let spanInputTag=document.getElementById("line");
/*span id="line"のonclickで起動する関数です*/
function toText(){
let keepLine=spanInputTag.innerHTML; //span id="line"の内容を変数に格納。
/*text要素を構築します*/
let textElement='<input type="text" id="line-text" value="'+keepLine+'" onblur="fromText()">';//idとonchangeを書きます valueに変更前の文字列を設定します
/*span id="line"にtext要素を配置します*/
spanInputTag.innerHTML=textElement;//ここでtext要素が出現します
/*text要素にフォーカスします*/
document.getElementById("line-text").focus();
document.getElementById("line-text").select();
/*span id="line"のonclickハンドラを無効にします*/
spanInputTag.onclick=null;//spanタグ内にselectタグあるので、selectタグへのクリックが上位spanタグに影響しないようにしています
}
/*input text id="line-text"のonblurで起動する関数です*/
function fromText(){//
let textTag=document.getElementById("line-text");
let getLine=textTag.value;//textで入力されたvalueを格納
/*span id="line"に入力された文字列を配置します*/
spanInputTag.innerHTML=getLine;//ここでtext要素と入力された文字列が入れ替わります
/*span id="line"にonclickを新たに配置します*/
spanInputTag.onclick=new Function("toText()");//nullにしたものを復活させます
}
</script>
</body>
</html>
さて、input-text要素に関してですが、
上記のJavaScriptでは、onblurで入力フォームが消えるようにしていますが、
onkeydownでEnterキーをトリガーにすることもできます。
更に上記のinput-text要素は、
value=""で入力フォームが消えてしまった場合の回避措置がありません。
value=""で消えてしまうとクリックすべき文字列がなくなりますので、次はもうクリックできません。
実際に使う場合は、value=""消えようとする時にアラート出すなりの回避措置が必要です。