[Vue.js]非推奨になったslot-scopeの代わりにv-slotを使う

# slot-scope
子コンポーネントから親コンポーネントにプロパティを渡すための構文。
**ScopedSlots**とこれを用いることでデータの振る舞いと見た目を分離することができる。

# TODOアプリ
簡単なTODOアプリのコードを例に使い方を見ていきます。
![qiita-vue-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166345/028f028e-5c2e-7905-93cf-7919f2a68b34.gif)

# Components
**Parent Component**

- App.vue 　 ←　全てのTodoを描画する

**Child Component**

- Todo.vue　　←　Todoの見た目を定義
- TodosData.vue　　←　TodoDataの振る舞いを定義

# slot-scopeとv-slot
Version 2.5以前はslot-scope
Version 2.6以降はslot-scopeとv-slot
が用意されている。
Vue 3.xからはslot-scopeはなくなるかもしれないので注意。
## 共通(Todo.vue, TodosData.vue)
```Vue:Todo.vue
<script>
export default {
  props: {
    todo: String,
    required: true,
    default: ''
  },
  methods: {
    handleTodoDone () {
      this.$emit('todoDone')
    }
  }
}
</script>

<template>
  <div>
    <span>
      {{ todo }}
    </span>
    <button @click="handleTodoDone">
      Done
    </button>
  </div>
</template>
```

```vue:TodosData.vue
<script>
export default {
  data () {
    return {
      todos: [],
      newTodoText: ''
    }
  },
  methods: {
    handleTodoDone (time) {
      for (let i = 0; i < this.todos.length; i++) {
        if (this.todos[i].time === time) this.todos.splice(i, 1)
      }
    },
    handleTodoAdd () {
      if (this.newTodoText === '') return
      const time = this.getTime()
      const newTodo = { text: this.newTodoText, time: time }
      this.todos.push(newTodo)
      this.newTodoText = ''
    },
    handleNewTodoChange (newTodo) {
      this.newTodoText = newTodo
    },
    getTime () {
      const now = new Date()
      const hour = String(now.getHours())
      const minute = String(now.getMinutes())
      const second = String(now.getSeconds())
      const time = hour + minute + second
      return time
    }
  },
  render (createElement) {
    return this.$scopedSlots.default({
      todos: this.todos,
      todoDone: this.handleTodoDone,
      todoAdd: this.handleTodoAdd,
      newTodoText: this.newTodoText,
      newTodoChange: this.handleNewTodoChange
    })[0]
  }
}
</script>
```
scopedSlotsを使うことで無駄なタグを生成せずに済む。

## Vue 2.5以前

```vue:App.vue
<script>
export default {
  components: { Todo, TodosData }
}
</script>

<template>
  <div>
    <todos-data>
      <template slot-scope="todosData">
        <div>
          <div>
            <input
              :value="todosData.newTodoText"
              type="text"
              @change="(e) => todosData.newTodoChange(e.target.value)"
            >
            <button @click="todosData.todoAdd">
              ADD
            </button>
          </div>
          <template v-for="todo in todosData.todos">
            <todo
              :todo="todo.text"
              :key="todo.time"
              @todoDone="todosData.todoDone(todo.time)"
            />
          </template>
        </div>
      </template>
    </todos-data>
  </div>
</template>
```
`slot-scope` 構文を用いてスロットプロパティを受け渡すには、親コンポーネントは `<template>` に対して `slot-scope` 属性を使う必要があります。

## Vue 2.6以降

```vue:App.vue
<script>
export default {
  components: { Todo, TodosData }
}
</script>

<template>
  <div>
    <todos-data v-slot="todosData">
      <div>
        <div>
          <input
            :value="todosData.newTodoText"
            type="text"
            @change="(e) => todosData.newTodoChange(e.target.value)"
          >
          <button @click="todosData.todoAdd">
            ADD
          </button>
        </div>
        <template v-for="todo in todosData.todos">
          <todo
            :todo="todo.text"
            :key="todo.time"
            @todoDone="todosData.todoDone(todo.time)"
          />
        </template>
      </div>
    </todos-data>
  </div>
</template>
```

`v-slot` 構文では、デフォルトスロットだけの場合はコンポーネントのタグをスロットのテンプレートとして使うことができます。
つまり、上記のように `TodosData` に記述することができます。

# え、一緒じゃん？
はい、書く位置が変わっただけでやっていることは変わっていません。
そもそもdeprecatedになった理由が、
**「コンポーネントがテンプレート内でどのプロパティを提供しているのかパッと見分かりにくい」**
というものだったので当然と言えば当然ですが。

# 終わりに
意外とまだ`slot-scope`を見かけるのでまとめてみました。
Vue.js楽しい！

# 補足
1. CSSは省略しています（というか色々端折ってます）
2. [Vue公式](https://jp.vuejs.org/v2/guide/components-slots.html#%E9%9D%9E%E6%8E%A8%E5%A5%A8%E3%81%AE%E6%A7%8B%E6%96%87)
3. [RFCs](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0001-new-slot-syntax.md)