シェルスクリプトマガジン

作りながら学ぶVue.js入門(Vol.99掲載)

著者:大津 真

JavaScriptフレームワークの中でも、学びやすさと柔軟さで人気を集めている「Vue.js」。本連載では、Vue.jsの基礎から実践的な使い方までを、分かりやすく丁寧に解説していきます。一緒にフロントエンド開発の楽しさを体験してみましょう。第4回では、v-onディレクティブの活用と、VueアプリケーションからDOM(Document Object Model)を操作する方法について説明します。

シェルスクリプトマガジン Vol.99は以下のリンク先でご購入できます。

図1 「event-props/src/App.vue」ファイルのコード

<script setup>
import { ref } from 'vue'

function eventTest(e) {
  console.log(e)
}
</script>

<template>
  <button @click="eventTest">Click me</button>
</template>

図1 「event-props/src/App.vue」ファイルのコード

<script setup>
import { ref } from 'vue'
const event = ref(null)

function eventTest(e) {
  event.value = e
}
</script>

<template>
  <div id="back" @click="eventTest" @dblclick="eventTest">
    <h1>Event Test</h1>
    <div id="box" @mouseover="eventTest" @mouseout="eventTest">
      <p>My Box</p>
    </div>
    <p>Event type: {{ event?.type }}</p>
    <p>x:{{ event?.clientX }} y: {{ event?.clientY }}</p>
  </div>
</template>

<style scoped>
#back {
  width: 100vw;
  height: 100vh;
}
#box {
  width: 100px;
  height: 100px;
  background-color: #f00;
  margin: 0 auto;
}
</style>

図6 「src/style.css」ファイルの変更例

(略)
#app {
  max-width: 1280px;
  margin: 0 auto;
  /* padding: 2rem; */  ←コメントにする
  text-align: center;
}
(略)

図7 useTemplateRef関数でDOM要素を取得するコードの例

<template>
(略)
  <img ref="fish" id="fish" src="./assets/fish1.jpg" />
(略)
</template>
<script setup>
(略)
  const fish = useTemplateRef("fish");
(略)
</script>

図8 「event-test2/src/App.vue」ファイルのコード

<!-- App.vue -->
<template>
  <div id="back" @click="moveImg">
    <img ref="fish" id="fish" src="./assets/fish1.jpg" />
  </div>
</template>

<script setup>
import { useTemplateRef, onMounted } from 'vue'
// テンプレート参照を取得
const fish_ref = useTemplateRef("fish")

function moveImg(e) {
  // transitionの設定
  const duration = "1s" // 移動時間
  fish_ref.value.style.transition = \
    left ${duration} ease, top ${duration} ease, \
    transform 0.3s ease

  // クリック位置に移動
  const x = e.clientX  - fish_ref.value.width / 2
  const y = e.clientY  - fish_ref.value.height / 2
  fish_ref.value.style.left = ${x}px
  fish_ref.value.style.top  = ${y}px

  // クリック方向に応じて向きを変える
  if (e.clientX < fish_ref.value.offsetLeft) {
    fish_ref.value.style.transform = 'scaleX(-1)' // 左向き
  } else {
    fish_ref.value.style.transform = 'scaleX(1)'  // 右向き
  }
}
</script>
<style scoped>
#back {
  position: fixed;
  inset: 0;
}
#fish {
  position: absolute;
  width: 100px;
  left:  100px; /* 初期位置 X */
  top:   100px; /* 初期位置 Y */
}
</style>

図10 HTMLテンプレート部分の変更箇所

(略)
<div id="back" @click="moveImg(false, $event)"
               @contextmenu="moveImg(true, $event)">
  <img ref="fish" id="fish" src="./assets/fish1.jpg" />
</div>
(略)

図11 JavaScript部分の変更箇所(抜粋)

(略)
function moveImg(isFast, e) {
  e.preventDefault(); // 右クリックメニューを防ぐ
(略)
  const duration = isFast ? "0.3s" : "0.8s";
  el.style.transition = left ${duration} ease, \
                        top ${duration} ease, \
                        transform 0.3s ease;
(略)

図12 不適切なコードの例

(略)
<script setup>
import { useTemplateRef, onMounted } from 'vue';

const fish = useTemplateRef("fish");

const el = fish.value
el.style.left = '100px'  // 左端の座標を設定
el.style.top  = '100px'  // 上端の座標を設定
(略)

図13 書き換えた部分のコード

onMounted(() => {
  const el = fish.value;
  if (el) {
    // 親要素の位置とサイズを取得
    const parentRect = el.offsetParent.getBoundingClientRect();
    // 初期位置を画面中央に設定
    const x = parentRect.width / 2 - el.width / 2;
    const y = parentRect.height / 2 - el.height / 2;
    el.style.left = ${x}px;
    el.style.top = ${y}px;
  }
});

※「&lt; 」を「<」に置き換えてください。