Vue コンポーネントにおけるロジック再利用のサンプル。Mixins から Composition API まで。
^3.0.0-rc.1
で動作確認しています。Composition API パターン以外は 2 系でも基本的には動くと思います。
サンプル
マウスカーソルのポジションを表示するコンポーネントをお題にしています。よくあるやつです。
まずは普通に
<template>{{ x }} {{ y }}</template> <script> export default { data() { return { x: 0, y: 0, }; }, mounted() { window.addEventListener("mousemove", this.update); }, unmounted() { window.removeEventListener("mousemove", this.update); }, methods: { update(e) { this.x = e.pageX; this.y = e.pageY; }, }, }; </script>
Mixins
<template>{{ x }} {{ y }}</template> <script> import mixinMouse from './mixin-mouse'; export default { mixins: [mixinMouse] }; </script>
mixin-mouse.js
export default { data() { return { x: 0, y: 0, }; }, mounted() { window.addEventListener("mousemove", this.update); }, unmounted() { window.removeEventListener("mousemove", this.update); }, methods: { update(e) { this.x = e.pageX; this.y = e.pageY; }, }, };
Higher-Order Components (HOCs)
Position.vue
<template>{{ x }} {{ y }}</template> <script> export default { props: ["x", "y"], }; </script>
with-mouse.js
import { h } from "vue"; export function hoc(inner) { return { data() { return { x: 0, y: 0, }; }, mounted() { window.addEventListener("mousemove", this.update); }, unmounted() { window.removeEventListener("mousemove", this.update); }, methods: { update(e) { this.x = e.pageX; this.y = e.pageY; }, }, render() { return h(inner, { x: this.x, y: this.y, }); }, }; }
import Position from "./components/Position.vue"; import withMouse from "./components/with-mouse"; const MousePosition = withMouse(Position);
Scoped Slots
React でいうところの Render Props
Mouse.vue
<template> <slot :mx="x" :my="y"></slot> </template> <script> export default { data() { return { x: 0, y: 0, }; }, mounted() { window.addEventListener("mousemove", this.update); }, unmounted() { window.removeEventListener("mousemove", this.update); }, methods: { update(e) { this.x = e.pageX; this.y = e.pageY; }, }, }; </script>
<Mouse> <template v-slot="{mx, my}">{{ mx }} {{ my }}</template> </Mouse>
Composition API
<template>{{ x }} {{ y }}</template> <script> import useMouse from "./use-mouse"; export default { setup() { const { x, y } = useMouse(); return { x, y }; }, }; </script>
use-mouse.js
import { ref, onMounted, onUnmounted } from 'vue' export default function useMouse() { const x = ref(0); const y = ref(0); function update(e) { x.value = e.pageX; y.value = e.pageY; } onMounted(() => { window.addEventListener("mousemove", update); }); onUnmounted(() => { window.removeEventListener("mousemove", update); }); return { x, y }; }