0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Vue.jsで要素クリックで編集画面を切り替える

Posted at

はじめに

最近はフロントエンドも覚えたいなという事でVue.jsを触り始めてます。
んで、最初からあまり大規模のものを作ろうとすると骨が折れるし途中で投げ出したくなるので
小さなものから作ってアウトプットしていこうと思い今回タイトルにある通りのもの作ってみた。

環境

  • Vue 3.2.26
  • StackBlitz

最近までブラウザ上で手軽に環境構築してくれて触れるサービス探していまして、
CodeSandBoxとかも触ってみたんですけれども見た目が自分好みという浅い理由でStackBlitz使ってます:relaxed:

まぁ、他にも色々理由はあるんですけどでも見た目って大事じゃないですか…?

(自分だけじゃないと思いたい)

作ってみた

はい、茶番はこれぐらいにして早速作ってみました!

まず、子コンポーネントの方から。
@click="editting"isEdit をフラグにして真偽値を切り替えてます。
それを v-if で見て表示・非表示させてます。

Card.vue
<template>
  <div class="card-wrapper">
    <div class="card">
      <div class="card-content" @click="editting" v-if="!isEdit">
        {{ name }}
      </div>
      <div class="edit-area" v-if="isEdit">
        <input
          class="edit-input-area"
          v-model="inputValue"
          @keyup.enter="saveContent"
          @keydown.esc="cancelEditing"
        />
        <div class="btn-area">
          <Button @click="saveContent">Edit</Button>
          <Button @click="cancelEditing">Cancel</Button>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import Button from './Button.vue';
export default {
  name: 'card',
  components: {
    Button,
  },
  data() {
    return {
      isEdit: false,
      inputValue: '',
    };
  },
  props: {
    id: {
      type: Number,
      required: true,
    },
    name: {
      type: String,
      required: true,
    },
    onupdate: {
      type: Function,
      required: true,
    },
  },
  methods: {
    editting() {
      this.isEdit = true;
      this.inputValue = this.name;
    },
    saveContent() {
      this.onupdate({ id: this.id, name: this.inputValue });
      this.isEdit = false;
    },
    cancelEditing() {
      this.isEdit = false;
    },
  },
};
</script>
<style scoped>
.card-wrapper {
  border: 0.5px solid;
  width: 180px;
  margin-top: 10px;
  padding: 5px;
  padding-bottom: 7px;
  border-radius: 3px;
}
.card {
}
.edit-area {
  margin-top: 5px;
  padding-right: 5px;
  padding-left: 5px;
}
.btn-area {
  display: flex;
  justify-content: center;
}
</style>

親コンポーネントの方になります。

CardList.vue
<template>
  <div>
    <ul>
      <li v-for="item in items" :key="item.id">
        <Card :="item" :onupdate="handleUpdate"></Card>
      </li>
    </ul>
  </div>
</template>
<script>
import Card from './Card.vue';
export default {
  name: 'CardList',
  components: {
    Card,
  },
  data() {
    return {
      shown: false,
      items: [
        {
          id: 1,
          name: 'ナポリタン',
        },
        {
          id: 2,
          name: 'キムチチャーハン',
        },
        {
          id: 3,
          name: '高菜明太マヨ牛丼',
        },
        {
          id: 4,
          name: 'チキン南蛮',
        },
      ],
    };
  },
  methods: {
    showForm() {
      this.shown = true;
    },
    handleUpdate(payload) {
      let idx = -1;
      for (let i = 0; i < this.items.length; i++) {
        if (this.items[i]['id'] === payload.id) {
          idx = i;
        }
      }
      if (idx === -1) {
        return;
      }
      this.items[idx] = payload;
    },
  },
};
</script>
<style scoped>
li {
  list-style-type: none;
}
</style>

なんか、子コンポーネントの方に色々と書きすぎてて依存関係を整理出来ていない感がありますが
精進していきます....

データの内容は自分の好きな食べ物 (誰も興味ないっと....:stuck_out_tongue_closed_eyes:)

StackBlitzのリンク貼っておく

終わりに

今回はちょっとだけ、親子コンポーネントの依存関係を体系的に理解できたかなと感じました。
んでも、まだまだななので頑張って継続していこうと思います。
お手すきの際には「ここはこうした方が良いよ」とかアドバイスなんか頂けると幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?