vue.js twitter 風 いいねボタンを押したときのアニメーション

Twitter風のいいねボタンを押したときのアニメーションを再現したい。

参考
https://codepen.io/robeen/pen/PbvJjy

上記の通りでコピペでできるんだが、デフォルトがオンという動作の方法がわからない。
コンポーネントにしたい。
使いまわしたい。

ということで自己流にした。

コピペで動く。

```app.SCSS

.heart-svg {
  cursor:pointer; overflow:visible; width:60px;//ここのサイズを変更すればサイズが変わる

  #heart{
    fill:#AAB8C2;//ねずみいろ
    transform-origin:center;
    animation:animateHeartOut 0s linear forwards;
  }

  #main-circ{transform-origin:29.5px 29.5px;}
}


.heart-on {
  fill:#E2264D !important;
}


.checkheart{display:none;}

.checkheart:checked + label svg{
  #heart{transform:scale(.2); fill:#E2264D; animation:animateHeart .3s linear forwards .25s;}
  #heart2{transform:scale(.2); fill:#E2264D; animation:animateHeart .3s linear forwards .25s;}

  #main-circ{transition:all 2s; animation:animateCircle .3s linear forwards; opacity:1;}
  #grp1{
    opacity:1; transition:.1s all .3s;
    #oval1{
      transform:scale(0) translate(0, -30px);
      transform-origin:0 0 0;
      transition:.5s transform .3s;}
    #oval2{
      transform:scale(0) translate(10px, -50px);
      transform-origin:0 0 0;
      transition:1.5s transform .3s;}
  }
  #grp2{
    opacity:1; transition:.1s all .3s;
    #oval1{
      transform:scale(0) translate(30px, -15px);
      transform-origin:0 0 0;
      transition:.5s transform .3s;}
    #oval2{
      transform:scale(0) translate(60px, -15px);
      transform-origin:0 0 0;
      transition:1.5s transform .3s;}
  }
  #grp3{
    opacity:1; transition:.1s all .3s;
    #oval1{
      transform:scale(0) translate(30px, 0px);
      transform-origin:0 0 0;
      transition:.5s transform .3s;}
    #oval2{
      transform:scale(0) translate(60px, 10px);
      transform-origin:0 0 0;
      transition:1.5s transform .3s;}
  }
  #grp4{
    opacity:1; transition:.1s all .3s;
    #oval1{
      transform:scale(0) translate(30px, 15px);
      transform-origin:0 0 0;
      transition:.5s transform .3s;}
    #oval2{
      transform:scale(0) translate(40px, 50px);
      transform-origin:0 0 0;
      transition:1.5s transform .3s;}
  }
  #grp5{
    opacity:1; transition:.1s all .3s;
    #oval1{
      transform:scale(0) translate(-10px, 20px);
      transform-origin:0 0 0;
      transition:.5s transform .3s;}
    #oval2{
      transform:scale(0) translate(-60px, 30px);
      transform-origin:0 0 0;
      transition:1.5s transform .3s;}
  }
  #grp6{
    opacity:1; transition:.1s all .3s;
    #oval1{
      transform:scale(0) translate(-30px, 0px);
      transform-origin:0 0 0;
      transition:.5s transform .3s;}
    #oval2{
      transform:scale(0) translate(-60px, -5px);
      transform-origin:0 0 0;
      transition:1.5s transform .3s;}
  }
  #grp7{
    opacity:1; transition:.1s all .3s;
    #oval1{
      transform:scale(0) translate(-30px, -15px);
      transform-origin:0 0 0;
      transition:.5s transform .3s;}
    #oval2{
      transform:scale(0) translate(-55px, -30px);
      transform-origin:0 0 0;
      transition:1.5s transform .3s;}
  }

  #grp2{opacity:1; transition:.1s opacity .3s;}
  #grp3{opacity:1; transition:.1s opacity .3s;}
  #grp4{opacity:1; transition:.1s opacity .3s;}
  #grp5{opacity:1; transition:.1s opacity .3s;}
  #grp6{opacity:1; transition:.1s opacity .3s;}
  #grp7{opacity:1; transition:.1s opacity .3s;}
}

@keyframes animateCircle{
  40%{transform:scale(10); opacity:1; fill:#DD4688;}
  55%{transform:scale(11); opacity:1; fill:#D46ABF;}
  65%{transform:scale(12); opacity:1; fill:#CC8EF5;}
  75%{transform:scale(13); opacity:1; fill:transparent; stroke:#CC8EF5; stroke-width:.5;}
  85%{transform:scale(17); opacity:1; fill:transparent; stroke:#CC8EF5; stroke-width:.2;}
  95%{transform:scale(18); opacity:1; fill:transparent; stroke:#CC8EF5; stroke-width:.1;}
  100%{transform:scale(19); opacity:1; fill:transparent; stroke:#CC8EF5; stroke-width:0;}
}

@keyframes animateHeart{
  0%{transform:scale(.2);}
  40%{transform:scale(1.2);}
  100%{transform:scale(1);}
}


```

Heartのコンポーネント


```Heart.vue


<template>

    <div>
        <div>


            このハートのIDは {{id}} です。
            現在の選択状況は {{res}} です。

            <div v-if="selected">


                <svg @click="check" class="heart-svg" viewBox="467 392 58 57" xmlns="http://www.w3.org/2000/svg">
                    <g id="Group" fill="none" fill-rule="evenodd" transform="translate(467 392)">
                        <path class="heart-on" d="M29.144 20.773c-.063-.13-4.227-8.67-11.44-2.59C7.63 28.795 28.94 43.256 29.143 43.394c.204-.138 21.513-14.6 11.44-25.213-7.214-6.08-11.377 2.46-11.44 2.59z" id="heart" fill="#E2264D" />
                        <circle id="main-circ" fill="#E2264D" opacity="0" cx="29.5" cy="29.5" r="1.5"/>
                        <g id="grp7" opacity="0" transform="translate(7 6)">
                            <circle id="oval1" fill="#9CD8C3" cx="2" cy="6" r="2"/>
                            <circle id="oval2" fill="#8CE8C3" cx="5" cy="2" r="2"/>
                        </g>

                        <g id="grp6" opacity="0" transform="translate(0 28)">
                            <circle id="oval1" fill="#CC8EF5" cx="2" cy="7" r="2"/>
                            <circle id="oval2" fill="#91D2FA" cx="3" cy="2" r="2"/>
                        </g>
                        <g id="grp3" opacity="0" transform="translate(52 28)">
                            <circle id="oval2" fill="#9CD8C3" cx="2" cy="7" r="2"/>
                            <circle id="oval1" fill="#8CE8C3" cx="4" cy="2" r="2"/>
                        </g>

                        <g id="grp2" opacity="0" transform="translate(44 6)">
                            <circle id="oval2" fill="#CC8EF5" cx="5" cy="6" r="2"/>
                            <circle id="oval1" fill="#CC8EF5" cx="2" cy="2" r="2"/>
                        </g>

                        <g id="grp5" opacity="0" transform="translate(14 50)">
                            <circle id="oval1" fill="#91D2FA" cx="6" cy="5" r="2"/>
                            <circle id="oval2" fill="#91D2FA" cx="2" cy="2" r="2"/>
                        </g>

                        <g id="grp4" opacity="0" transform="translate(35 50)">
                            <circle id="oval1" fill="#F48EA7" cx="6" cy="5" r="2"/>
                            <circle id="oval2" fill="#F48EA7" cx="2" cy="2" r="2"/>
                        </g>

                        <g id="grp1" opacity="0" transform="translate(24)">
                            <circle id="oval1" fill="#9FC7FA" cx="2.5" cy="3" r="2"/>
                            <circle id="oval2" fill="#9FC7FA" cx="7.5" cy="2" r="2"/>
                        </g>
                    </g>
                </svg>

                                <div style="height: 8px;"></div>

            </div>

            <div v-else>

                <input type="checkbox" class="checkheart" :id="field" @click="check" v-model="msg"/>
                <label :for="field">
                    <svg class="heart-svg" viewBox="467 392 58 57" xmlns="http://www.w3.org/2000/svg">
                        <g id="Group" fill="none" fill-rule="evenodd" transform="translate(467 392)">

                            <path d="M29.144 20.773c-.063-.13-4.227-8.67-11.44-2.59C7.63 28.795 28.94 43.256 29.143 43.394c.204-.138 21.513-14.6 11.44-25.213-7.214-6.08-11.377 2.46-11.44 2.59z" id="heart" fill="#AAB8C2" />

                            <circle id="main-circ" fill="#E2264D" opacity="0" cx="29.5" cy="29.5" r="1.5"/>

                            <g id="grp7" opacity="0" transform="translate(7 6)">
                                <circle id="oval1" fill="#9CD8C3" cx="2" cy="6" r="2"/>
                                <circle id="oval2" fill="#8CE8C3" cx="5" cy="2" r="2"/>
                            </g>

                            <g id="grp6" opacity="0" transform="translate(0 28)">
                                <circle id="oval1" fill="#CC8EF5" cx="2" cy="7" r="2"/>
                                <circle id="oval2" fill="#91D2FA" cx="3" cy="2" r="2"/>
                            </g>

                            <g id="grp3" opacity="0" transform="translate(52 28)">
                                <circle id="oval2" fill="#9CD8C3" cx="2" cy="7" r="2"/>
                                <circle id="oval1" fill="#8CE8C3" cx="4" cy="2" r="2"/>
                            </g>

                            <g id="grp2" opacity="0" transform="translate(44 6)">
                                <circle id="oval2" fill="#CC8EF5" cx="5" cy="6" r="2"/>
                                <circle id="oval1" fill="#CC8EF5" cx="2" cy="2" r="2"/>
                            </g>

                            <g id="grp5" opacity="0" transform="translate(14 50)">
                                <circle id="oval1" fill="#91D2FA" cx="6" cy="5" r="2"/>
                                <circle id="oval2" fill="#91D2FA" cx="2" cy="2" r="2"/>
                            </g>

                            <g id="grp4" opacity="0" transform="translate(35 50)">
                                <circle id="oval1" fill="#F48EA7" cx="6" cy="5" r="2"/>
                                <circle id="oval2" fill="#F48EA7" cx="2" cy="2" r="2"/>
                            </g>

                            <g id="grp1" opacity="0" transform="translate(24)">
                                <circle id="oval1" fill="#9FC7FA" cx="2.5" cy="3" r="2"/>
                                <circle id="oval2" fill="#9FC7FA" cx="7.5" cy="2" r="2"/>
                            </g>
                        </g>
                    </svg>
                </label>
            </div>

        </div>
    </div>

</template>

<script>
    export default {
        props: ['id','firstSelect'],
        data() {
            return {
                res:'',
                field:'',
                msg:false,
            }
        },

        created(){

            this.selected = this.firstSelect;
            this.res = this.firstSelect;

            this.field = 'heart' + this.id;

        },

        methods: {
            check(){


                if(this.selected){
                    this.res = false;
                } else {
                    if(this.msg){
                        this.res = false;
                    } else {
                        this.res = true;
                    }
                }
                this.selected = false;
                this.$emit('heartSelect',this.id,this.res);

            }
        }
    }
</script>



```


あとは、使うだけ。
非同期読み込みだと、後で値が渡らないので、同期で読み出す。

```Top.vue

    import heart from './Heart'
    export default {
        components: {
            heart
        },

        data () {
            return {
//子要素にわたす
                id:'777',


        <heart :id="id" :firstSelect="true" @heartSelect="heartSelect"></heart>
        <heart :id="id" :firstSelect="false" @heartSelect="heartSelect"></heart>



        methods: {


            heartSelect(id,bool){


                console.log(id);//どのIDが
                console.log(bool);//true or false?


            },

```