0. はじめに
-
MYJLab Advent Calendar 2019 7日目の記事です。
-
顔、髪、眉、目、鼻、口の形をそれぞれ6種類から選択することができ、位置や大きさ、角度を変更することができます。
-
デモページはこちら
1. 実行環境
エディタ : CodeSandbox
CodeSandbox
- https://codesandbox.io/
- オンラインコードエディター
- Vue.jsのフレームワークを簡単に使うことができる。
- ライブラリやコンポーネントの追加も簡単に行うことができる。
CodeSandboxでVue.jsのプロジェクトを立ち上げる方法
- CodeSandboxを開く。
- 右上の Sign In をクリックする。
- GitHubアカウントでサインインする。アカウントがない場合は Create an account からアカウントを作成する。
- Authorize codesandbox をクリックする。サインインが終了する。
- 右上の検索部分でvueを検索する。
- 画像と同じものをクリックする。
- 右上のForkをクリックする。
- Vue.jsのプロジェクトの立ち上げが完了した。
2. プロジェクト概要
- Vue.js+SVGで自由にCSSアニメーションしたい人のための完全解説(ソース付き)を参考にさせていただいています。
用意したもの
- 画像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. プロジェクト解説
部位選択
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>
### 形選択
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;
} ...
}
### アバターとパーツの移動、大きさ・角度変更
(初期の顔が一番面白い気がする。。。)
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)から
props
でisFace
(クリックされた顔の形の画像の参照先)を受け取り、選択された画像表示する。
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がいつの間にか登録しないと使えなくなっていた、、、
- 顔のパーツの素材を見つけられなくて苦労してしまった。
- コンポーネント間の値の受け渡しやスタイルのバインディングの復習になりました。