アプリ版:「スタンプのみでお礼する」機能のリリースについて

javascriptで以下のような処理を作るにはどういう形で作ればいいですか?

①2つの選択肢AとB(わかりやすいようにボタンにする)

②選択肢の「Aボタン」を押すと①に戻る
     「Bボタン」を押すと③に進む

③3つの選択肢CとDとE「ボタン」の画面が出る
↓CかDかEボタンを押すか、時間経過(例えば3秒)で④に進む

④3つの選択肢FとGとH「ボタン」の画面が出る
→同様にボタンを押すか、時間経過で①に戻る

console.logに ”一回目はBとDとH”
"二回目はA"
”三回目はBとCとF”みたいな感じで表示させたいです

A 回答 (6件)

こんな感じでしょうか。



<head>
<meta charset="UTF-8">
<title>doc</title>
<style>
div{
display:none;
}
div:first-child{
display:block;
}
</style>
</head>
<body>
<div>
<button id="s">スタート</button>
</div>
<div>
<button id="a">Aボタン</button>
<button id="b">Bボタン</button>
</div>
<div>
<button id="c">Cボタン</button>
<button id="d">Dボタン</button>
<button id="e">Eボタン</button>
</div>
<div>
<button id="f">Fボタン</button>
<button id="g">Gボタン</button>
<button id="h">Hボタン</button>
</div>
<script>
const D_ELM = [...document.querySelectorAll('div')],
B_ELM = [...document.querySelectorAll('button')];
let num = 0;
let timer;

function changeDiv(prev, next){
if(prev === 0){
num += 1;
console.log(num + '回目');
}
if(next > 1){
timer = window.setTimeout(()=>{
changeDiv(prev + 1, (next + 1) % 4);
},3000);
}
D_ELM.forEach(elm => {elm.style.display = 'none'});
D_ELM[next].style.display = 'block';
}

document.addEventListener('click', e =>{
window.clearTimeout(timer)
if(B_ELM.includes(e.target)) {
let btn = e.target.id;
let prev = 0;
let next = 1;
switch (btn) {
case 's':
[prev, next] = [0, 1];
break;
case 'a':
[prev, next] = [1, 0];
break;
case 'b':
[prev, next] = [1, 2];
break;
case 'c':
case 'd':
case 'e':
[prev, next] = [2, 3];
break;
case 'f':
case 'g':
case 'h':
[prev, next] = [3, 0];
break;
}
changeDiv(prev, next);
console.log(btn);
}
}, false);
</script>
</body>
    • good
    • 0

No1です。


すみません、switchだとあまりにも長くなるので、修正しました。
HTML部分は一緒です。


const D = [...document.querySelectorAll('div')],
B = [...document.querySelectorAll('button')];
let num = 0, // 回目
push = []; // 押したボタンを覚える
let timer; // 押さないときに先に進む

function changeDiv(prev, next){
next %= 4;
if(next === 0){
num += 1;
console.log(num + '回目は ' + push.join('と'));
push = [];
}
if(next > 1){
timer = window.setTimeout(()=>{
changeDiv(prev + 1, next + 1);
},3000);
}
D.forEach(elm => {elm.style.display = 'none'});
D[next].style.display = 'block';
}

document.addEventListener('click', e =>{
window.clearTimeout(timer)
if(B.includes(e.target)) {
if(e.target.id === 'a'){ // Aボタンのときだけ戻る
push.push('a');
changeDiv(1, 0);
return;
}
let btn = D.indexOf(e.target.parentNode);
push.push(e.target.id);
changeDiv(btn, btn + 1);
}
}, false);
    • good
    • 1

全角空白は半角に置換してください


もっと細分化できそうですが、あきらめました。
HTMLから制御できます

bottan#id が数字なら使えませんよ・・・

<!DOCTYPE hrml>
<meta charset="utf-8">
<title></title>
<style>
ol { list-style: none; }
ol li:not(.current) {
 display: none;
}
</style>


<body>

<ol>
 <li class="current begin">
  <button value="a" class="end">Aボタン</button>
  <button value="b">Bボタン</button>
 
 <li data-wait="3000">
  <button value="c">Cボタン</button>
  <button value="d">Dボタン</button>
  <button value="e">Eボタン</button>

 <li data-wait="3000">
  <button value="f">Fボタン</button>
  <button value="g">Gボタン</button>
  <button value="h">Hボタン</button>
</ol>

<script>

const
 obj = {
  stock: [ ],
  timerId: null,
  count: 0,
  _current: null,

  reset: function () {
   let
    begin = document.querySelector ('li.begin, ol>li:first-of-type'),//ここは収集があまい
    ol = begin.parentNode;

   this.stock = [ ];
   begin.classList.add ('current');
   return this;
  },


  choice: function (btn) {
   this.stock.push (btn.value);
   this.current = btn.classList.contains ('end') ? null: btn.closest ('li');
   return this;
  },


  next: function () {
   let e = this.current;
   if (e) {
    e.classList.remove ('current');
    this.current = e = e.nextElementSibling;
    if (e) {
     e.classList.add ('current');
     return this;
    }
   }
   return this.end ();
  },


  end : function () {
   console.log (`${++this.count} 回目は、${this.stock.join(' と ')} です`);
   return this.reset ();
  },


  set current (e) {
   if (this.timerId)
    this.timerId = clearInterval (this.timerId) || null;

   if (this._current = e) {
    let wait = parseInt (e.dataset.wait, 10);
    if (! isNaN (wait))
     this.timerId = setInterval (this.next.bind (this), wait);
   }
  },


  get current () {
   return this._current;
  },
  

  handleEvent: function ({target: e}) {
   if ('BUTTON' === e.nodeName)
    if (e.closest ('li.current'))
     this.choice (e).next ();
  }
 };


document.addEventListener ('click', obj, false);

</script>
    • good
    • 1

#3です


修正します。もっと set current に集約するべきでした。

<!DOCTYPE hrml>
<meta charset="utf-8">
<title></title>
<style>
ol { list-style: none; }
ol li:not(.current) {
 display: none;
}
</style>


<body>

<ol>
 <li class="current begin">
  <button value="a" class="end">Aボタン</button>
  <button value="b">Bボタン</button>
 
 <li data-wait="3000">
  <button value="c">Cボタン</button>
  <button value="d">Dボタン</button>
  <button value="e">Eボタン</button>

 <li data-wait="3000">
  <button value="f">Fボタン</button>
  <button value="g">Gボタン</button>
  <button value="h">Hボタン</button>
</ol>

<script>

const
 obj = {
  stock: [ ],
  timerId: null,
  count: 0,
  _current: null,

  reset: function () {
   this.current = document.querySelector ('li.begin, ol>li:first-of-type');//ここは収集があまい;
   this.stock = [ ];
   return this;
  },


  choice: function (btn) {
   this.stock.push (btn.value);
   this.current = btn.classList.contains ('end') ? null: btn.closest ('li');
   return this;
  },


  next: function (e = this.current) {
   if (e)
    if (this.current = e = e.nextElementSibling)
     return this;
   return this.end ();
  },


  end : function () {
   console.log (`${++this.count} 回目は、${this.stock.join(' と ')} です`);
   return this.reset ();
  },


  set current (e) {
   if (this.timerId)
    this.timerId = clearInterval (this.timerId) || null;
   
   if (this._current)
    this._current.classList.remove ('current');

   if (this._current = e) {
    e.classList.add ('current');
    let wait = parseInt (e.dataset.wait, 10);
    if (! isNaN (wait))
     this.timerId = setInterval (this.next.bind (this), wait);
   }
  },


  get current () {
   return this._current;
  },
  

  handleEvent: function ({target: e}) {
   if ('BUTTON' === e.nodeName)
    if (e.closest ('li.current'))
     this.choice (e).next ();
  }
 };


document.addEventListener ('click', obj, false);

</script>
    • good
    • 0

#3,4 です。


寝ぼけてました。
以下修正。
setInterval -> setTimeout
clearInterval -> clearTimeout
    • good
    • 1

こんにちは



>処理の構想が知りたいです
構想は人それぞれです。
ご質問程度の内容であれば、基本的な考え方には大きな差はでないと思いますけれど、それをどのように具体化するかは様々ですね。
マークアップの方法も人それぞれと言えますので・・。

「様々」の例として、一例を以下に。

・①と②では、画面は変わらずに、Aを押した時だけカウントアップして
 出力するものと解釈しました。
・時間制限でボタンが押されなかった場合は、出力では無視してよいものと
 解釈しました。(押されないという内容も出力されない)
・時間制限があるのは、③と④のみで、①、②は制限はないとしています。

<!DOCTYPE HTML>
<html lang="ja">
<head><title>Sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
#hoge fieldset{
width: 12em; margin-top: 1.6em; border: 0;
display: none; justify-content: space-around;
}
#hoge fieldset.active { display: flex; }
#hoge button{ width: 3.4em; }
#hoge legend{
width: 100%; margin: .8em 0;
font-weight: bold; text-align: center;
background-color: lavender;
}
</style>
</head>
<body>

<div id="hoge">
<fieldset>
<legend>①,②の選択肢</legend>
<button type="button" value="A">A</button>
<button type="button" value="B">B</button>
</fieldset>

<fieldset>
<legend>③の選択肢</legend>
<button type="button" value="C">C</button>
<button type="button" value="D">D</button>
<button type="button" value="E">E</button>
</fieldset>

<fieldset>
<legend>④の選択肢</legend>
<button type="button" value="F">F</button>
<button type="button" value="G">G</button>
<button type="button" value="H">H</button>
</fieldset>
</div>

<script>
window.addEventListener('DOMContentLoaded', ()=>{
const
LimitTime = 3000, /*** 制限時間(msec) ***/

elm = document.getElementById('hoge'),
fields = elm.querySelectorAll('fieldset'),
buttons = [...elm.querySelectorAll('button')],
p = { count: 1, mode: 0, records: [], timerID: null },

Log = ()=>{
console.log(`${ p.count++}回目は${p.records.join('と')}`);
[p.mode, p.records] = [0, []];
},
Next = ()=>{
clearTimeout(p.timerID);
fields.forEach((e, i)=>{ e.className = i == p.mode? 'active':''; });
if(p.mode) p.timerID = setTimeout(Check, LimitTime);
},
Check = ()=>{
if( ++p.mode >= fields.length) Log();
Next();
},

ClickHandler = (e)=>{
const t = e.target, n = buttons.indexOf(t);
if( n < 0 ) return;
p.records.push(t.value);
if( n == 0 ) p.mode = fields.length;
Check();
};

Next();
elm.addEventListener('click', ClickHandler);

});
</script>
</body>
</html>
    • good
    • 1

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!