LoginSignup
14
3

More than 3 years have passed since last update.

Vue.jsでアバター作成

Last updated at Posted at 2019-12-06

0. はじめに

  • MYJLab Advent Calendar 2019 7日目の記事です。
  • Vue.jsとCodeSandboxでアバター(のようなもの)が作成できるツールを作成しました。
    vue.gif

  • 顔、髪、眉、目、鼻、口の形をそれぞれ6種類から選択することができ、位置や大きさ、角度を変更することができます。

  • デモページはこちら

1. 実行環境

エディタ : CodeSandbox

CodeSandbox

  • https://codesandbox.io/
  • オンラインコードエディター
  • Vue.jsのフレームワークを簡単に使うことができる。
  • ライブラリやコンポーネントの追加も簡単に行うことができる。

CodeSandboxでVue.jsのプロジェクトを立ち上げる方法

  1. CodeSandboxを開く。
  2. 右上の Sign In をクリックする。 codesandbox1.png
  3. GitHubアカウントでサインインする。アカウントがない場合は Create an account からアカウントを作成する。codesandbox2.png
  4. Authorize codesandbox をクリックする。サインインが終了する。codesandbox3.png
  5. 右上の検索部分でvueを検索する。codesandbox4.png
  6. 画像と同じものをクリックする。codesandbox5.png
  7. 右上のForkをクリックする。codesandbox6.png
  8. Vue.jsのプロジェクトの立ち上げが完了した。

2. プロジェクト概要

用意したもの

  • 画像48枚
    • ヘッダー用の画像(顔、髪、眉、目、鼻、口):6枚
    • 顔、髪、眉、目、鼻、口の形を選択する用の画像それぞれ6枚ずつ:36枚
    • 大きさ、位置、角度変更用の矢印の画像:6枚
      (せっかく作ったので、GitHubにあげたりしてここにアップロードしたい。。。)

はじめに

  • publicフォルダ内にimgフォルダを作成し、上記の画像48枚をアップロードする。

  • components内のHelloWorld.vueをFace.vueに名称変更する。

フォルダ構成

├ public/
│  ├ img/
│  │ └ face.pngなど48枚
│  ├ favicon.ico
│  └ index.html
├ src/
│  ├ assets/
│  │ └ logo.png
│  ├ components
│  │ └ Face.vue
│  ├ App.vue
│  └ main.js
└ package.json

ファイルの中身

App.vue

App.vue
<template>
 <div id="app">
  <header>
    <div id="parts">
      <ul>
        <li @click="status='face'">
          <img src="/img/face.png" height="70px;">
        </li>
        <li @click="status='hair'">
          <img src="/img/hair.png" height="70px;">
        </li>
        <li @click="status='eyebrow'">
          <img src="/img/eyebrow.png" height="70px;">
        </li>
        <li @click="status='eye'">
          <img src="/img/eye.png" height="70px;">
        </li>
        <li @click="status='nose'">
          <img src="/img/nose.png" height="70px;">
        </li>
        <li @click="status='mouth'">
          <img src="/img/mouth.png" height="70px;">
        </li>
      </ul>
    </div>

    <div id="form">
      <ul v-for="index of 6" :key="index">
        <li @click="isClick(index)">
          <img :src="getImgUrl(index)" height="70px;">
        </li>
      </ul>
    </div>
  </header>
  <body>
    <Face :isFace="isFace" :isHair="isHair" :isEyebrow="isEyebrow" :isEye="isEye" :isNose="isNose" :isMouth="isMouth" />
  </body>
 </div>
</template>

<script>
import Face from "./components/Face.vue";

export default {
  name: "app",
  components: {
    Face,
  },
  data() {
    return {
      status: "face",
      isFace:"/img/face1.png",
      isHair:"/img/hair1.png",
      isEyebrow:"/img/eyebrow1.png",
      isEye:"/img/eye1.png",
      isNose:"/img/nose1.png",
      isMouth:"/img/mouth1.png"
    };
  },
  methods: {
    getImgUrl(index) {
      var images = "/img/" + this.status + index + ".png";
      return images;
    },
      isClick(index) {
      var images = "/img/" + this.status + index + ".png";
        if(this.status === "face"){
          this.isFace = images
          return this.isFace;
        } else if(this.status === "hair"){
          this.isHair = images
          return this.isHair;
        }else if(this.status === "eyebrow"){
          this.isEyebrow = images
          return this.isEyebrow;
        }else if(this.status === "eye"){
          this.isEye = images
          return this.isEye;
        }else if(this.status === "nose"){
          this.isNose = images
          return this.isNose;
        }else{
          this.isMouth = images
          return this.isMouth;
        }
    },
  }
};
</script>

<style scoped>
html,
body {
  margin: 0;
  padding: 0;
}
body {
  position: relative;
  height: 100%;
}
#parts {
  padding: 3px;
  background-color: #000000;
}
#parts ul {
  padding: 0px;
  margin: 0px;
}
#parts ul li {
  display: inline;
  margin-left: 1em;
}
#form {
  padding: 3px;
  background-color: #c0c0c0;
}
#form ul {
  display: inline;
  padding: 0px;
  margin: 0px;
}
#form ul li {
  display: inline;
  margin-left: 1em;
}
</style>

Face.vue

Face.vue
<template>
  <div id="app">
    <div>
      <img
        class="arrangement"
        :src="isFace"
        alt=""
        :style="{
      transform: `translate(${faceX}px, ${faceY}px) scale(${faceScaleX}, ${faceScaleY}) rotate(${faceRotate}deg)`
    }"
      >
      <img
        class="arrangement"
        :src="isEyebrow"
        alt="左眉"
        :style="{
      transform: `translate(${lefteyebrowX}px, ${lefteyebrowY}px) scale(${eyebrowScaleX}, ${eyebrowScaleY}) rotate(${lefteyebrowRotate}deg)`
    }"
      >
      <img
        class="arrangement"
        :src="isEyebrow"
        alt="右眉"
        :style="{
      transform: `translate(${righteyebrowX}px, ${righteyebrowY}px) scale(-${eyebrowScaleX}, ${eyebrowScaleY}) rotate(${righteyebrowRotate}deg)`
    }"
      >
      <img
        class="arrangement"
        :src="isEye"
        alt="左目"
        :style="{
      transform: `translate(${lefteyeX}px, ${lefteyeY}px) scale(${eyeScaleX}, ${eyeScaleY}) rotate(${lefteyeRotate}deg)`
    }"
      >
      <img
        class="arrangement"
        :src="isEye"
        alt="右目"
        :style="{
      transform: `translate(${righteyeX}px, ${righteyeY}px) scale(-${eyeScaleX}, ${eyeScaleY}) rotate(${righteyeRotate}deg)`
    }"
      >
      <img
        class="arrangement"
        :src="isNose"
        alt=""
        :style="{
      transform: `translate(${noseX}px, ${noseY}px) scale(${noseScaleX}, ${noseScaleY}) rotate(${noseRotate}deg)`
    }"
      >
      <img
        class="arrangement"
        :src="isMouth"
        alt=""
        :style="{
      transform: `translate(${mouthX}px, ${mouthY}px) scale(${mouthScaleX}, ${mouthScaleY}) rotate(${mouthRotate}deg)`
    }"
      >
      <img
        class="arrangement"
        :src="isHair"
        alt=""
        :style="{
      transform: `translate(${hairX}px, ${hairY}px) scale(${hairScaleX}, ${hairScaleY}) rotate(${hairRotate}deg)`
    }"
      >
    </div>
    <div id="leftContents">
      <h3></h3>
      <p>
        位置 :
        <img src="/img/arrow1.png" width="25px;" @click="faceY=faceY-10">
        <img src="/img/arrow1.png" width="25px;" class="rotate180" @click="faceY=faceY+10">
        <img src="/img/arrow1.png" width="25px;" class="rotate270" @click="faceX=faceX-10">
        <img src="/img/arrow1.png" width="25px;" class="rotate90" @click="faceX=faceX+10">
      </p>
      <p>
        サイズ
        <img src="/img/arrow2.png" width="25px;" @click="faceScaleY=faceScaleY+0.1">
        <img
          src="/img/arrow2.png"
          width="25px;"
          class="rotate90"
          @click="faceScaleX=faceScaleX+0.1"
        >
        <img src="/img/arrow3.png" width="25px;" @click="faceScaleY=faceScaleY-0.1">
        <img
          src="/img/arrow3.png"
          width="25px;"
          class="rotate90"
          @click="faceScaleX=faceScaleX-0.1"
        >
      </p>
      <p>
        回転 :
        <img
          src="/img/arrow4.png"
          width="25px;"
          style="transform: scale(-1, 1);"
          @click="faceRotate=faceRotate-1"
        >
        <img src="/img/arrow4.png" width="25px;" @click="faceRotate=faceRotate+1">
      </p>
      <h3></h3>
      <p>
        位置 :
        <img src="/img/arrow1.png" width="25px;" @click="hairY=hairY-10">
        <img src="/img/arrow1.png" width="25px;" class="rotate180" @click="hairY=hairY+10">
        <img src="/img/arrow1.png" width="25px;" class="rotate270" @click="hairX=hairX-10">
        <img src="/img/arrow1.png" width="25px;" class="rotate90" @click="hairX=hairX+10">
      </p>
      <p>
        サイズ
        <img src="/img/arrow2.png" width="25px;" @click="hairScaleY=hairScaleY+0.1">
        <img
          src="/img/arrow2.png"
          width="25px;"
          class="rotate90"
          @click="hairScaleX=hairScaleX+0.1"
        >
        <img src="/img/arrow3.png" width="25px;" @click="hairScaleY=hairScaleY-0.1">
        <img
          src="/img/arrow3.png"
          width="25px;"
          class="rotate90"
          @click="hairScaleX=hairScaleX-0.1"
        >
      </p>
      <p>
        回転 :
        <img
          src="/img/arrow4.png"
          width="25px;"
          style="transform: scale(-1, 1);"
          @click="hairRotate=hairRotate-1"
        >
        <img src="/img/arrow4.png" width="25px;" @click="hairRotate=hairRotate+1">
      </p>
            <h3></h3>
          <p>
        位置 :
        <img
          src="/img/arrow1.png"
          width="25px;"
          @click="lefteyebrowY=lefteyebrowY-2; righteyebrowY=righteyebrowY-2;"
        >
        <img
          src="/img/arrow1.png"
          width="25px;"
          class="rotate180"
          @click="lefteyebrowY=lefteyebrowY+2; righteyebrowY=righteyebrowY+2;"
        >
        <img
          src="/img/arrow1.png"
          width="25px;"
          class="rotate270"
          @click="lefteyebrowX=lefteyebrowX-2; righteyebrowX=righteyebrowX-2;"
        >
        <img
          src="/img/arrow1.png"
          width="25px;"
          class="rotate90"
          @click="lefteyebrowX=lefteyebrowX+2; righteyebrowX=righteyebrowX+2;"
        >
        <img
          src="/img/arrow2.png"
          width="25px;"
          class="rotate90"
          @click="lefteyebrowX=lefteyebrowX+2; righteyebrowX=righteyebrowX-2;"
        >
        <img
          src="/img/arrow3.png"
          width="25px;"
          class="rotate90"
          @click="lefteyebrowX=lefteyebrowX-2; righteyebrowX=righteyebrowX+2;"
        >
      </p>
      <p>
        サイズ
        <img src="/img/arrow2.png" width="25px;" @click="eyebrowScaleY=eyebrowScaleY+0.02">
        <img src="/img/arrow2.png" width="25px;" class="rotate90" @click="eyebrowScaleX=eyebrowScaleX+0.02">
        <img src="/img/arrow3.png" width="25px;" @click="eyebrowScaleY=eyebrowScaleY-0.02">
        <img src="/img/arrow3.png" width="25px;" class="rotate90" @click="eyebrowScaleX=eyebrowScaleX-0.02">
      </p>
      <p>
        回転 :
        <img src="/img/arrow5.png" width="25px;" @click="lefteyebrowRotate=lefteyebrowRotate+1; righteyebrowRotate=righteyebrowRotate+1;">
        <img src="/img/arrow6.png" width="25px;" @click="lefteyebrowRotate=lefteyebrowRotate-1; righteyebrowRotate=righteyebrowRotate-1;">
      </p>
    </div>
    <div id="rightContents">
    <h3></h3>
          <p>
        位置
        <img
          src="/img/arrow1.png"
          width="25px;"
          @click="lefteyeY=lefteyeY-2; righteyeY=righteyeY-2;"
        >
        <img
          src="/img/arrow1.png"
          width="25px;"
          class="rotate180"
          @click="lefteyeY=lefteyeY+2; righteyeY=righteyeY+2;"
        >
        <img
          src="/img/arrow1.png"
          width="25px;"
          class="rotate270"
          @click="lefteyeX=lefteyeX-2; righteyeX=righteyeX-2;"
        >
        <img
          src="/img/arrow1.png"
          width="25px;"
          class="rotate90"
          @click="lefteyeX=lefteyeX+2; righteyeX=righteyeX+2;"
        >
        <img
          src="/img/arrow2.png"
          width="25px;"
          class="rotate90"
          @click="lefteyeX=lefteyeX+2; righteyeX=righteyeX-2;"
        >
        <img
          src="/img/arrow3.png"
          width="25px;"
          class="rotate90"
          @click="lefteyeX=lefteyeX-2; righteyeX=righteyeX+2;"
        >
      </p>
      <p>
        サイズ
        <img src="/img/arrow2.png" width="25px;" @click="eyeScaleY=eyeScaleY+0.02">
        <img src="/img/arrow2.png" width="25px;" class="rotate90" @click="eyeScaleX=eyeScaleX+0.02">
        <img src="/img/arrow3.png" width="25px;" @click="eyeScaleY=eyeScaleY-0.02">
        <img src="/img/arrow3.png" width="25px;" class="rotate90" @click="eyeScaleX=eyeScaleX-0.02">
      </p>
      <p>
        回転 :
        <img src="/img/arrow5.png" width="25px;" @click="lefteyeRotate=lefteyeRotate+1; righteyeRotate=righteyeRotate+1;">
        <img src="/img/arrow6.png" width="25px;" @click="lefteyeRotate=lefteyeRotate-1; righteyeRotate=righteyeRotate-1;">
      </p>

      <h3></h3>
      <p>
        位置 :
        <img src="/img/arrow1.png" width="25px;" @click="noseY=noseY-2">
        <img src="/img/arrow1.png" width="25px;" class="rotate180" @click="noseY=noseY+2">
        <img src="/img/arrow1.png" width="25px;" class="rotate270" @click="noseX=noseX-2">
        <img src="/img/arrow1.png" width="25px;" class="rotate90" @click="noseX=noseX+2">
      </p>
      <p>
        サイズ
        <img src="/img/arrow2.png" width="25px;" @click="noseScaleY=noseScaleY+0.02">
        <img
          src="/img/arrow2.png"
          width="25px;"
          class="rotate90"
          @click="noseScaleX=noseScaleX+0.02"
        >
        <img src="/img/arrow3.png" width="25px;" @click="noseScaleY=noseScaleY-0.02">
        <img
          src="/img/arrow3.png"
          width="25px;"
          class="rotate90"
          @click="noseScaleX=noseScaleX-0.02"
        >
      </p>
      <p>
        回転 :
        <img
          src="/img/arrow4.png"
          width="25px;"
          style="transform: scale(-1, 1);"
          @click="noseRotate=noseRotate-1"
        >
        <img src="/img/arrow4.png" width="25px;" @click="noseRotate=noseRotate+1">
      </p>

      <h3></h3>
      <p>
        位置 :
        <img src="/img/arrow1.png" width="25px;" @click="mouthY=mouthY-2">
        <img src="/img/arrow1.png" width="25px;" class="rotate180" @click="mouthY=mouthY+2">
        <img src="/img/arrow1.png" width="25px;" class="rotate270" @click="mouthX=mouthX-2">
        <img src="/img/arrow1.png" width="25px;" class="rotate90" @click="mouthX=mouthX+2">
      </p>
      <p>
        サイズ
        <img src="/img/arrow2.png" width="25px;" @click="mouthScaleY=mouthScaleY+0.02">
        <img
          src="/img/arrow2.png"
          width="25px;"
          class="rotate90"
          @click="mouthScaleX=mouthScaleX+0.02"
        >
        <img src="/img/arrow3.png" width="25px;" @click="mouthScaleY=mouthScaleY-0.02">
        <img
          src="/img/arrow3.png"
          width="25px;"
          class="rotate90"
          @click="mouthScaleX=mouthScaleX-0.02"
        >
      </p>
      <p>
        回転 :
        <img
          src="/img/arrow4.png"
          width="25px;"
          style="transform: scale(-1, 1);"
          @click="mouthRotate=mouthRotate-1"
        >
        <img src="/img/arrow4.png" width="25px;" @click="mouthRotate=mouthRotate+1">
      </p>

    </div>
  </div>
</template>

<script>
export default {
  name: "Face",
  props: {
    isFace: { type: String, default: "/img/face1.png" },
    isHair: { type: String, default: "/img/hair1.png" },
    isEyebrow: { type: String, default: "/img/eyebrow1.png" },
    isEye: { type: String, default: "/img/eye1.png" },
    isNose: { type: String, default: "/img/nose1.png" },
    isMouth: { type: String, default: "/img/mouth1.png" },
  },
  data() {
    return {
      faceX: 100,
      faceY: 100,
      faceScaleX: 1,
      faceScaleY: 1,
      faceRotate: 0,
      hairX: 100,
      hairY: 100,
      hairScaleX: 1,
      hairScaleY: 1,
      hairRotate: 0,
      lefteyebrowX: 250,
      lefteyebrowY: -100,
      lefteyebrowRotate: 0,
      righteyebrowX: 170,
      righteyebrowY: -100,
      righteyebrowRotate: 0,
      eyebrowScaleX: 0.2,
      eyebrowScaleY: 0.2,
      lefteyeX: 250,
      lefteyeY: -60,
      lefteyeRotate: 0,
      righteyeX: 170,
      righteyeY: -60,
      righteyeRotate: 0,
      eyeScaleX: 0.2,
      eyeScaleY: 0.2,
      noseX: 190,
      noseY: 0,
      noseScaleX: 0.2,
      noseScaleY: 0.2,
      noseRotate: 0,
      mouthX: 190,
      mouthY: 50,
      mouthScaleX: 0.2,
      mouthScaleY: 0.2,
      mouthRotate: 0
    };
  }
};
</script>

<style scoped>
#app {
  width: 100%;
  display: flex;
}
#leftContents {
  padding-left: 600px;
}
#rightContents {
  padding-left: 100px;
}
.arrangement {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 90px 100%;
}
.rotate90 {
  -webkit-transform: rotate(90deg);
  -moz-transform: rotate(90deg);
  -o-transform: rotate(90deg);
  -ms-transform: rotate(90deg);
  transform: rotate(90deg);
}
.rotate180 {
  -webkit-transform: rotate(180deg);
  -moz-transform: rotate(180deg);
  -o-transform: rotate(180deg);
  -ms-transform: rotate(180deg);
  transform: rotate(180deg);
}
.rotate270 {
  -webkit-transform: rotate(270deg);
  -moz-transform: rotate(270deg);
  -o-transform: rotate(270deg);
  -ms-transform: rotate(270deg);
  transform: rotate(270deg);
}
h3 {
  position: relative;
  padding: 10px 0 0 25px;
}
h3:before {
  position: absolute;
  content: '';
  bottom: -3px;
  left: 0;
  width: 0;
  height: 0;
  border: none;
  border-left: solid 15px transparent;
  border-bottom: solid 15px rgb(119, 195, 223);
}
h3:after {
  position: absolute;
  content: '';
  bottom: -3px;
  left: 10px;
  width: 100%;
  border-bottom: solid 3px rgb(119, 195, 223);
}
</style>
  • プロジェクトの中身はこちらからも確認できます。

3. プロジェクト解説

部位選択

vue1.png

App.vue
<template>
  <div id="parts">
    <header>
      <ul>
        <li @click="status='face'">
          <img src="/img/face.png" height="70px;">
        </li>
        <li @click="status='hair'">
          <img src="/img/hair.png" height="70px;">
        </li>
        <li @click="status='eyebrow'">
          <img src="/img/eyebrow.png" height="70px;">
        </li>
        <li @click="status='eye'">
          <img src="/img/eye.png" height="70px;">
        </li>
        <li @click="status='nose'">
          <img src="/img/nose.png" height="70px;">
        </li>
        <li @click="status='mouth'">
          <img src="/img/mouth.png" height="70px;">
        </li>
      </ul>
    </header>
  </div>
</template>

<script>
export default {
  data() {
    return {
      status: "face",
    };
  }
};
</script>

<style scoped>
#parts {
  padding: 3px;
  background-color: #000000;
}
#parts ul {
  padding: 0px;
  margin: 0px;
}
#parts ul li {
  display: inline;
  margin-left: 1em;
}
  • 顔、髪、眉、目、鼻、口の画像をリストを使って表示する。
  • クリックされるとstatusに対応した値が入る。初期値はface
<ul>
  <li @click="status='face'"> //@clickでクリックされた時の処理
     <img src="/img/face.png" height="70px;"> //顔の画像を表示
  </li>
  <li @click="status='hair'">
     <img src="/img/hair.png" height="70px;">
   </li>
...
</ul>


形選択

vue2.png

App.vue
<template>
  <header>
    <div id="form">
      <ul v-for="index of 6" :key="index">
        <li @click="isClick(index)">
          <img :src="getImgUrl(index)" height="70px;">
        </li>
      </ul>
    </div>
  </header>
</template>

<script>
export default {
  data() {
    return {
      isFace:"/img/face1.png",
      isHair:"/img/hair1.png",
      isEyebrow:"/img/eyebrow1.png",
      isEye:"/img/eye1.png",
      isNose:"/img/nose1.png",
      isMouth:"/img/mouth1.png",
    };
  },
  methods: {
    getImgUrl(index) {
      var images = "/img/" + this.status + index + ".png";
      return images;
    },
    isClick(index) {
      var images = "/img/" + this.status + index + ".png";
        if(this.status === "face"){
          this.isFace = images
          return this.isFace;
        } else if(this.status === "hair"){
          this.isHair = images
          return this.isHair;
        }else if(this.status === "eyebrow"){
          this.isEyebrow = images
          return this.isEyebrow;
        }else if(this.status === "eye"){
          this.isEye = images
          return this.isEye;
        }else if(this.status === "nose"){
          this.isNose = images
          return this.isNose;
        }else{
          this.isMouth = images
          return this.isMouth;
        }
    }
  }
};
</script>

<style scoped>
#form {
  padding: 3px;
  background-color: #c0c0c0;
}
#form ul {
  display: inline;
  padding: 0px;
  margin: 0px;
}
#form ul li {
  display: inline;
  margin-left: 1em;
}
</style>
  • statusの値に応じて画像が変化する。
    • 上の画像ではstatus === 'face'なので、顔の画像が表示されている。
  • それぞれ画像を6枚ずつ用意しているので、v-for="index of 6"で6枚の画像を表示する。
<ul v-for="index of 6" :key="index">
  <li @click="isClick(index)">
     <img :src="getImgUrl(index)" height="70px;">
   </li>
</ul>
  • getImgUrl(index)ではファイルの参照先を返している。
    • 画像名はface1.png, face2.png ... mouth5.png, mouth6.pngとなっているので、status + index + ".png"で参照先が示せる。
getImgUrl(index) {
   var images = "/img/" + this.status + index + ".png";
   return images;
}
  • isClick(index) では子コンポーネント(Face.vue)にクリックした画像の情報を送る。
    • 変数:isFace、isHair、isEyebrow、isEye、isNose、isMouthにクリックしたファイルの参照先を保持している。
isClick(index) {
  var images = "/img/" + this.status + index + ".png";
  if(this.status === "face"){             //faceがクリックされたら顔を変更
    this.isFace = images
    return this.isFace;
  } else if(this.status === "hair") {     //hairがクリックされたら髪を変更
    this.isHair = images
    return this.isHair;
  } ...
}


アバターとパーツの移動、大きさ・角度変更

vue3.png

(初期の顔が一番面白い気がする。。。)

App.vue
<template>
  <body>
    <Face :isFace="isFace" :isHair="isHair" :isEyebrow="isEyebrow" :isEye="isEye" :isNose="isNose" :isMouth="isMouth" />
  </body>
</template>

<script>
import Face from "./components/Face.vue";

export default {
  components: {
    Face,
  },
  data() {
    return {
      isFace:"/img/face1.png",
      isHair:"/img/hair1.png",
      isEyebrow:"/img/eyebrow1.png",
      isEye:"/img/eye1.png",
      isNose:"/img/nose1.png",
      isMouth:"/img/mouth1.png",
    };
  },
};
</script>
  • Face.vueをインポートして呼び出す。
import Face from "./components/Face.vue";

export default {
  components: {
    Face,
  },
...
  • 先ほどの変数:isFace ... isMouthを受け渡すために:isFace="isFace"...<Face>タグ内に記入する。
<Face :isFace="isFace" :isHair="isHair" :isEyebrow="isEyebrow" :isEye="isEye" :isNose="isNose" :isMouth="isMouth" />
// 親から子に変数を渡す時は :変数名 = "渡したい値"  
Face.vue

<template>
    <div>
      <img
        class="arrangement"
        :src="isFace"
        alt=""
        :style="{
      transform: `translate(${faceX}px, ${faceY}px) scale(${faceScaleX}, ${faceScaleY}) rotate(${faceRotate}deg)`
    }"
      >

    <div id="leftContents">
      <h3></h3>
      <p>
        位置 :
        <img src="/img/arrow1.png" width="25px;" @click="faceY=faceY-10">
        <img src="/img/arrow1.png" width="25px;" class="rotate180" @click="faceY=faceY+10">
        <img src="/img/arrow1.png" width="25px;" class="rotate270" @click="faceX=faceX-10">
        <img src="/img/arrow1.png" width="25px;" class="rotate90" @click="faceX=faceX+10">
      </p>
      <p>
        サイズ
        <img src="/img/arrow2.png" width="25px;" @click="faceScaleY=faceScaleY+0.1">
        <img
          src="/img/arrow2.png"
          width="25px;"
          class="rotate90"
          @click="faceScaleX=faceScaleX+0.1"
        >
        <img src="/img/arrow3.png" width="25px;" @click="faceScaleY=faceScaleY-0.1">
        <img
          src="/img/arrow3.png"
          width="25px;"
          class="rotate90"
          @click="faceScaleX=faceScaleX-0.1"
        >
      </p>
      <p>
        回転 :
        <img
          src="/img/arrow4.png"
          width="25px;"
          style="transform: scale(-1, 1);"
          @click="faceRotate=faceRotate-1"
        >
        <img src="/img/arrow4.png" width="25px;" @click="faceRotate=faceRotate+1">
      </p>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    isFace: { type: String, default: "/img/face1.png" },
  },
  data() {
    return {
      faceX: 100,
      faceY: 100,
      faceScaleX: 1,
      faceScaleY: 1,
      faceRotate: 0
    };
  }
};
</script>

<style scoped>
#app {
  width: 100%;
  display: flex;
}
#leftContents {
  padding-left: 600px;
}
.arrangement {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 90px 100%;
  /* transform: translate(200px, 100px); */
}
.rotate90 {
  -webkit-transform: rotate(90deg);
  -moz-transform: rotate(90deg);
  -o-transform: rotate(90deg);
  -ms-transform: rotate(90deg);
  transform: rotate(90deg);
}
.rotate180 {
  -webkit-transform: rotate(180deg);
  -moz-transform: rotate(180deg);
  -o-transform: rotate(180deg);
  -ms-transform: rotate(180deg);
  transform: rotate(180deg);
}
.rotate270 {
  -webkit-transform: rotate(270deg);
  -moz-transform: rotate(270deg);
  -o-transform: rotate(270deg);
  -ms-transform: rotate(270deg);
  transform: rotate(270deg);
}
h3 {
  position: relative;
  padding: 10px 0 0 25px;
}
h3:before {
  position: absolute;
  content: '';
  bottom: -3px;
  left: 0;
  width: 0;
  height: 0;
  border: none;
  border-left: solid 15px transparent;
  border-bottom: solid 15px rgb(119, 195, 223);
}
h3:after {
  position: absolute;
  content: '';
  bottom: -3px;
  left: 10px;
  width: 100%;
  border-bottom: solid 3px rgb(119, 195, 223);
}
</style>
  • 親コンポーネント(App.vue)からpropsisFace(クリックされた顔の形の画像の参照先)を受け取り、選択された画像表示する。
  props: {
    isFace: { type: String, default: "/img/face1.png" },
  }
  • translate(${faceX}px, ${faceY}px)が位置を、scale(${faceScaleX}, ${faceScaleY})が大きさを、rotate(${faceRotate}deg)が角度を表している。
<img class="arrangement"
     :src="isFace" //親から受け取った画像の参照先にある画像を表示
     alt=""
     :style="{
       transform: `translate(${faceX}px, ${faceY}px) scale(${faceScaleX}, 
       ${faceScaleY}) rotate(${faceRotate}deg)`
     }"
>
  • data()でfaceX、faceY、faceScaleX、faceScaleY、faceRotateの初期値を定義しておく。
data() {
    return {
      faceX: 100,
      faceY: 100,
      faceScaleX: 1,
      faceScaleY: 1,
      faceRotate: 0
    };
  • 矢印を押すことで、faceX、faceY、faceScaleX、faceScaleY、faceRotateの値を変更するため、位置、大きさ、角度が変更される。
    • 例えば、位置の左矢印はクリックされるごとにfaceXの値が10ずつ減少していき、顔の画像が左に移動していく。
 <img src="/img/arrow1.png" width="25px;" class="rotate270" @click="faceX=faceX-10">
  • 髪、眉、目、鼻、口も同様になっている。

4. おわりに

反省点

  • cssが適当すぎる。
  • 組み合わせ次第では髪から顔がはみ出し、面白いことになってしまう。
  • もう少し画像を増やしたい。
  • 眼鏡とか髭とかほくろとかも追加したかった。

そのほか

  • CodeSandboxがいつの間にか登録しないと使えなくなっていた、、、
  • 顔のパーツの素材を見つけられなくて苦労してしまった。
  • コンポーネント間の値の受け渡しやスタイルのバインディングの復習になりました。
14
3
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
14
3