質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.58%

あいうえお順に並んでほしい【javascript?】

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,887

terame120

score 14

ttps://cr-vue.mio3io.com/tutorials/todo.html
こちらを参考に、自分用にアプリを作りたいと思っています。
初心者で、全部を理解できていない状況です。

作っているのは、ことばの管理用のアプリです。
URLの先を参考に、
・ことば、かなを登録する
・「メモ(未記入)」、「記入済」という2つの振り分けをできるようにする
・振り分け先が別のページになるようにする
というところまでできました。

そして次に絶対ほしい機能が、『記入済のページのみ(かなの頭文字で)あいうえお順に並ぶこと』です。
あいうえお順からまた別の形に変える機能はつけません。
未記入ページは登録順に並んでほしいのですが、これは今のままで達成されています。

先ほどまで調べつつ試していましたが、さっぱり分からず進展がなく、自分で解決することが難しく感じたので、質問してみることにしました。
どのようにすればあいうえお順に並べることができるか、方法またはアドバイスを頂けますと幸いです。

イメージ説明

以下、すべてのコードです。

write.html【ここから追加すると<notyet.html><done.html>にことばが追加されていきます】

<!doctype html>
<html><head>
<meta charset="utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript" src="main.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title></title>
</head>



<body>
    <div id="app">

    <!-- ★STEP11 -->

          <label v-for="label in options" >
      <input type="radio"
        v-model="current"
        v-bind:value="label.value">{{ label.label }}
    </label>
    <!-- ★STEP12 -->
    ({{ computedTodos.length }} 件を表示)

    <!-- ★STEP4 リスト用テーブル -->
    <table>
      <thead v-pre>
        <tr>
          <th class="id">ID</th>
          <th class="comment">ことば</th>
          <th class="kana">かな</th>
            <th class="state">状態</th>
          <th class="button">-</th>
        </tr>
      </thead>
      <tbody>
        <!-- ★STEP5 ToDo の要素をループ -->
        <tr
          v-for="item in computedTodos"
          v-bind:key="item.id"
          v-bind:class="{done:item.state}">
          <th>{{ item.id }}</th>
          <td>{{ item.comment }}</td>
            <td>{{ item.kana }}</td>
          <td class="state">
            <!-- ★STEP10 状態変更ボタン -->
            <button v-on:click="doChangeState(item)">
              {{ labels[item.state] }}
            </button>
          </td>
          <td class="button">
            <!-- ★STEP10 削除ボタン -->
            <button v-on:click.ctrl="doRemove(item)">
              削除
            </button>
          </td>
        </tr>
      </tbody>
    </table>
      <p>※削除ボタンはコントロールキーを押しながらクリックして下さい</p></div>




</body>
</html>

notyet.html
文字数が収まりきらないので割愛

done.html【こちらをあいうえお順にしたい】

<!doctype html>
<html><head>
<meta charset="utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript" src="main.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title></title>
</head>



<body>
    <div id="appp">

    <!-- ★STEP11 -->
          <label v-for="label in options" >
      <input type="radio"
        v-model="current"
        v-bind:value="label.value">{{ label.label }}
    </label>

    <!-- ★STEP12 -->
    ({{ computedTodos.length }} 件を表示)

    <!-- ★STEP4 リスト用テーブル -->
    <table>
      <thead v-pre>
        <tr>
          <th class="kana">かな</th>
          <th class="comment">ことば</th>
          <th class="id">ID</th>
          <th class="state">状態</th>
          <th class="button">-</th>
        </tr>
      </thead>
      <tbody>
        <!-- ★STEP5 ToDo の要素をループ -->
        <tr
          v-for="item in computedTodos"
          v-bind:key="item.id"
          v-bind:class="{done:item.state}">
          <td>{{ item.kana }}</td>
          <td>{{ item.comment }}</td>
          <td>{{ item.id }}</td>
          <td class="state">
            <!-- ★STEP10 状態変更ボタン -->
            <button v-on:click="doChangeState(item)">
              {{ labels[item.state] }}
            </button>
          </td>
          <td class="button">
            <!-- ★STEP10 削除ボタン -->
            <button v-on:click.ctrl="doRemove(item)">
              削除
            </button>
          </td>
        </tr>
      </tbody>
    </table>
      <p>※削除ボタンはコントロールキーを押しながらクリックして下さい</p></div>


</body>
</html>

main.js

// ★STEP2
// https://jp.vuejs.org/v2/examples/todomvc.html
var STORAGE_KEY = 'todos-vuejs-demo'
var todoStorage = {
  fetch: function () {
    var todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]')
    todos.forEach(function (todo, index) {
      todo.id = index
    })
    todoStorage.uid = todos.length
    return todos
  },
  save: function (todos) {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(todos))
  }
}


// ★STEP1
document.addEventListener("DOMContentLoaded", function(event) {
new Vue({
  el: '.app',

  data: {
    // ★STEP5 localStorage から 取得した ToDo のリスト
    todos: [],
    // ★STEP11 抽出しているToDoの状態
    current: -1,
    // ★STEP11&STEP13 各状態のラベル
    options: [
      { value: -1, label: 'すべて' },
      { value: 0, label: '未記入' },
      { value: 1, label: '記入済' }
    ]
  },

  computed: {

    // ★STEP12
    computedTodos: function () {
      return this.todos.filter(function (el) {
        return this.current < 0 ? true : this.current === el.state
      }, this)
    },

    // ★STEP13 作業中・完了のラベルを表示する
    labels() {
      return this.options.reduce(function (a, b) {
        return Object.assign(a, { [b.value]: b.label })
      }, {})
      // キーから見つけやすいように、次のように加工したデータを作成
      // {0: '作業中', 1: '完了', -1: 'すべて'}
    }
  },

  // ★STEP8
  watch: {
    // オプションを使う場合はオブジェクト形式にする
    todos: {
      // 引数はウォッチしているプロパティの変更後の値
      handler: function (todos) {
        todoStorage.save(todos)
      },
      // deep オプションでネストしているデータも監視できる
      deep: true
    }
  },

  // ★STEP9
  created() {
    // インスタンス作成時に自動的に fetch() する
    this.todos = todoStorage.fetch()
  },

  methods: {

    // ★STEP7 ToDo 追加の処理
    doAdd: function(event, value) {
      // ref で名前を付けておいた要素を参照
      var comment = this.$refs.comment,
          kana = this.$refs.kana,
          val= $('.add-form [name=stts]:checked').val()
      // 入力がなければ何もしないで return
      if (!comment.value.length) {
        return
      }
      // { 新しいID, コメント, 作業状態 }
      // というオブジェクトを現在の todos リストへ push
      // 作業状態「state」はデフォルト「作業中=0」で作成
      this.todos.push({
        id: todoStorage.uid++,
        comment: comment.value,
        kana: kana.value,
        state: Number(val)
      })
      // フォーム要素を空にする
      comment.value = '',
      kana.value = ''
    },

    // ★STEP10 状態変更の処理
    doChangeState: function (item) {
      item.state = !item.state ? 1 : 0
    },

    // ★STEP10 削除の処理
    doRemove: function (item) {
      var index = this.todos.indexOf(item)
      this.todos.splice(index, 1)
    }

  }
})
})

document.addEventListener("DOMContentLoaded", function(event) {
new Vue({
  el: '#appp',

  data: {
    // ★STEP5 localStorage から 取得した ToDo のリスト
    todos: [],
    // ★STEP11 抽出しているToDoの状態
    current: 1,
    // ★STEP11&STEP13 各状態のラベル
    options: [
      { value: 1, label: '記入済' }
    ]
  },

  computed: {

    // ★STEP12
    computedTodos: function () {
      return this.todos.filter(function (el) {
        return this.current < 0 ? true : this.current === el.state
      }, this)
    },

    // ★STEP13 作業中・完了のラベルを表示する
    labels() {
      return this.options.reduce(function (a, b) {
        return Object.assign(a, { [b.value]: b.label })
      }, {})
      // キーから見つけやすいように、次のように加工したデータを作成
      // {0: '作業中', 1: '完了', -1: 'すべて'}
    }
  },

  // ★STEP8
  watch: {
    // オプションを使う場合はオブジェクト形式にする
    todos: {
      // 引数はウォッチしているプロパティの変更後の値
      handler: function (todos) {
        todoStorage.save(todos)
      },
      // deep オプションでネストしているデータも監視できる
      deep: true
    }
  },

  // ★STEP9
  created() {
    // インスタンス作成時に自動的に fetch() する
    this.todos = todoStorage.fetch()
  },

  methods: {

    // ★STEP7 ToDo 追加の処理
        doAdd: function(event, value) {
      // ref で名前を付けておいた要素を参照
      var comment = this.$refs.comment,
          kana = this.$refs.kana,
          val= $('.add-form [name=stts]:checked').val()
      // 入力がなければ何もしないで return
      if (!comment.value.length) {
        return
      }
      // { 新しいID, コメント, 作業状態 }
      // というオブジェクトを現在の todos リストへ push
      // 作業状態「state」はデフォルト「作業中=0」で作成
      this.todos.push({
        kana: kana.value,
        comment: comment.value,
        id: todoStorage.uid++,
        state: Number(val)
      })
      // フォーム要素を空にする
      comment.value = '',
      kana.value = ''
    },
    // ★STEP10 状態変更の処理
    doChangeState: function (item) {
      item.state = !item.state ? 1 : 0
    },

    // ★STEP10 削除の処理
    doRemove: function (item) {
      var index = this.todos.indexOf(item)
      this.todos.splice(index, 1)
    }

  }
})
})
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

「配列の要素を、特定の条件で並び替えたい」ということだとおもいますので、
Array.prototype.sort()メソッドが使えます。

var array = [1, 3, 2, 5, 4];

var sortedArray = array.sort(function(a, b) {
  return a - b;
});

console.log(sortedArray); // -> [1, 2, 3, 4, 5]

質問のケースでは、もとの配列を並び替えてしまうと、未記入ページでも並びが変わってしまうので、
computedプロパティで、必要に応じて、別の並び替えた配列を返すようにします。

new Vue({
  data() {
    return {
       // 登録順の配列を想定
      todos: [
        { kana: 'う' },
        { kana: 'あ' },
        { kana: 'い' }
      ]
    }
  },
  computed: {
    sortedTodos: function() {
      var copiedTodos = this.todos.slice(); // 配列の要素をコピー

      return copiedTodos.sort(function(a, b) {
        return a - b;
      });
    }
  }
});

参考リンク
Vue.jsのリスト(配列)レンダリング

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/30 01:26

    こちらでもご回答をいただきありがとうございます。
    computedプロパティからその順番でデータを返すようにすることが必要だということが分かりました。
    しばらく自分なりに試してみましたが、うまくできず、変わらずIDの数値で並んでいるので、疑問点をお聞きしたいです。

    ①記入済みの表示はmain.jsのel:#appp指定から行い、登録はel:#appから行っているのですが、この場合コードの記述は#apppで良いでしょうか。それとも新しくnew Vueを記述するのでしょうか。
    #apppで良い場合、すでにcomputed:{に振り分けのための記述があるのですが、書く順番は特に決まりはないでしょうか。

    ②保存されている配列はkana以外の要素もあり、
    [ { "id": ●, "comment": "ことば", "kana"="かな,"state": ● },...]
    といった形で収まっていると思うのですが、この場合kanaの文字列を参照させるための操作はあるでしょうか?
    または登録時にkanaが先頭に来るようにするとよいでしょうか。
    (kanaが先頭にくるよう自分なりにやってみましたがうまくいかず…)

    ③参考にしたサイトのJSでは、ひとつも;がなく、すべて,でつながれているのですが、(別のサイトを参考にしたとき;を入れるとJavascriptが動かなくなることがほとんどで…)(こちらのコードを;が入ったままで挿入してみたところjavascriptが働いていない様子はありませんでした)
    こちらのコードでの;の扱いは、ないと通用しないのか、なくてもなんとかなるのか、分かれば教えていただけると嬉しいです。



    computed: {
    sortedTodos: function() {
    var copiedTodos = this.todos.slice(); // 配列の要素をコピー

    return copiedTodos.sort(function(a, b) {
    return a - b;
    });
    }
    を#apppのcompured:{に入れるという形で、その周辺をいじって反応を見ていましたが、成功せず、勉強不足の身で何度も伺ってしまい恐縮なのですが、可能な範囲でアドバイスを頂けましたら嬉しいです。(説明が下手で状況が伝わらなかったら申し訳ありません。)

    キャンセル

  • 2018/12/01 17:28

    この後また考えて、main.jsの#apppの場所のcompted内、すでにあったcomputedTodo:{以下に記述するとやりやすいと分かりました。
    sortが働いている気がしますが、(sort以外の要素を排しても配列がきちんと表示されるので)並び順は変わらないため、idを参照してソートしているのかなと推測しています。
    全くの見当違いでしたら申し訳ありませんが、.sortを使用する際に、オブジェクトのなかのあるデータを参照する方法はありますでしょうか。

    htmlのほうで@click="sortBy('kana')"の要素を入れるとソートするボタンが作れるようにも思いましたが、最初から並んでいてほしいので、その方法が知りたいです。
    アドバイスを頂けないでしょうか。

    キャンセル

  • 2018/12/02 11:46

    できました。a.kana b.kanaでよかったのですね。
    また、ひらがなのソートのコードのことも知らずにおりました。
    しつこく聞いて申し訳ありませんでした。ヒントをありがとうございました。とても助かりました。

    キャンセル

  • 2018/12/02 14:56

    返信できておらず、すみません。
    解決したようでよかったです。

    内容をみる限り、Vue.jsよりも、JavaScriptの構文(文法)であいまいな部分があるようですので、一度ざっと見返すことをおすすめします。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.58%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る