Vue.jsで子コンポーネントの関数やCSSを触る

# 概要

AtomicDesignを使った設計を行っている際に、子コンポーネントの関数を親側で使用したり、CSSの変更が行えないかと調査したことをまとめます。

AtomicDesignに則り以下のようなフォルダ構成でフロントエンド環境を構築しています。

```
C:.
├─assets
│  └─icon
├─components
│  ├─atoms
│  ├─molecules
│  ├─organisms
│  └─pages
└─router
```
今回は以下の2つのファイルを用意しました。
.../molecules/inputWithButton
.../pages/Parent

これらを使って子コンポーネントの関数を親側で使用したり、CSSの変更を行ったりします。

画面イメージはこちらです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2699390/c458b698-0f92-e6ab-b1d3-432912856686.png)
子ボタン（子コンポーネント内に設置）を押下するとアラートが表示されます。

## ソース
子コンポーネント
```vuejs:inputWithButton.vue
<template>
    <div>
    <br>
        <input class="inputClass" :type="type" :disabled="disabled"/>
        <button
            class="buttton"
            @click="click"
        >子ボタン</button>
    </div>

</template>

<script>

export default {
  name: 'InputWithButton',
  components: {
  },
  data () {
    return {}
  },
  props: {
    type: {
      type: String,
      default: "text",
    },
    value: {
      type: String,
      default: "",
    },
    disabled: {
      type: Boolean,
      default: false,
    }
  },
  methods: {
      click() {
          alert("pushed");
      }
  },
}
</script>
```

親コンポーネント
```vuejs:Parent.vue
<template>
    <div>
        <InputWithButton type="input"/>
        <br>
        <button @click="parentClick">親ボタン</button>
    </div>
</template>

<script>
import InputWithButton from "@/components/molecules/InputWithButton.vue";

export default {
  name: "Parent",
  data() {
    return {

    };
  },
  components: {
      InputWithButton
  },
  methods: {
      parentClick(){
      }
  },
  computed: {},
};
</script>

```

## $refs
[公式のドキュメント](https://vuejs.org/guide/essentials/template-refs.html#ref-on-component)を見ると、`ref`を使うことで子コンポーネントに参照IDを付与することができるとありましたので付与します。

```vuejs:inputWithButton.vue
<template>
    <div ref="childButton">
    <br>
        <input ref="input-area" class="inputClass" :type="type" :disabled="disabled"/>
        <button
            class="buttton"
            @click="click"
        >子ボタン</button>
    </div>

</template>
```

2行目のdivに付与した`ref="childButton"`によって、子コンポーネント自体を参照できるようになり、inputタグにつけた`ref="inputArea"`によってinputボックスが参照できるようになります。

続いて親側でも同様にrefで参照できるようにし、コンソールで確認できるように記述します。
refで名前をつけたものは`this.$refs`で参照できます。

```vuejs:Parent.vue
<template>
    <div>
        <InputWithButton ref="childButton" type="input"/>
        <br>
        <button @click="parentClick">親ボタン</button>
    </div>
</template>

<script>
import InputWithButton from "@/components/molecules/InputWithButton.vue";

export default {
  name: "Parent",
  data() {
    return {

    };
  },
  components: {
      InputWithButton
  },
  methods: {
      parentClick(){
          console.log(this.$refs)
      }
  },
  computed: {},
};
</script>
```

ここで、親ボタンを押下し、中身を確認すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2699390/8cdf5eed-33f4-75b1-796d-9781029679d8.png)

子コンポーネントが参照できていることがわかります。
まずは子コンポーネントのボタン押下時にアラートを出すメソッドを参照し、親コンポーネントのボタン押下時にも同様のアクションが起こせるようにします。
```vuejs:Parent.vue
  methods: {
      parentClick(){
        console.log(this.$refs)
        this.$refs.childButton.click()
      }
  },
```

このようにコンソール画面を展開する軌跡を`.`で記述していくことで親コンポーネントで用意したボタンを押下した際に、子コンポーネントで定義した関数を使うことができます。


次に、子コンポーネントのCSSを親コンポーネントのボタン押下をきっかけに変更します。
inputの背景色を黄色にしてみます。
先ほど同様、参照したコンポーネント内を探していき、以下の記述で操作できました。
```vuejs:Parent.vue
  methods: {
      parentClick(){
        console.log(this.$refs)
        this.$refs.childButton.click()
        this.$refs.childButton.$refs.inputArea.style["background-color"] = "yellow"
      }
  },
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2699390/937be340-9818-f762-06df-d214022cc014.png)


# まとめ
refをコンポーネントや要素に付与することで直接DOMの操作が行えるということでした。
再利用可能なコンポーネントを使用した開発を行う上で必要な場面があるかと思いますので参考になれば幸いです。