一、ディレクティブ修飾子
1.概要
ディレクティブ修飾子とは、"."を使用してディレクティブのサフィックスを指定するものです。異なるサフィックスが異なる処理操作をカプセル化します。これによりコードを簡素化できます。
2.キーボード修飾子——@keyup
@keyup.enter → Enterキーが押されたときにのみトリガーされます(キーボードのEnterキーを監視)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>キーボードイベントの監視</title>
</head>
<body>
<div id="app">
<h3>@keyup.enter → Enterキーイベントの監視</h3>
<input @keyup.enter="handleEnter" v-model="userName" type="text">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
userName: ''
},
methods: {
handleEnter(event) {
console.log('Enterキーが押されました', this.userName)
}
}
})
</script>
</body>
</html>
3.v-model修飾子
v-model.trim→ 先頭と末尾のスペースを削除v-model.number→ 数値に変換
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-model修飾子の使用例</title>
</head>
<body>
<div id="app">
<h3>v-model修飾子 .trim .number</h3>
お名前:<input v-model.trim="userName" type="text"><br>
年齢:<input v-model.number="userAge" type="text"><br>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
userName: '',
userAge: '',
}
})
</script>
</body>
</html>
4.イベント修飾子
@イベント名.stop→ イベントのバブリングを停止@イベント名.prevent→ デフォルトの動作を防止@イベント名.stop.prevent→ 連用可能。イベントのバブリングとデフォルトの動作の両方を防止
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>イベント修飾子のデモ</title>
<style>
.parent {
width: 200px;
height: 200px;
background-color: rgb(52, 72, 50);
margin-top: 20px;
}
.child {
width: 100px;
height: 100px;
background-color: rgb(132, 185, 134);
}
</style>
</head>
<body>
<div id="app">
<h3>@イベント名.stop → バブリングの停止</h3>
<div @click="parentClick" class="parent">
<div @click.stop="childClick" class="child">子要素</div>
</div>
<h3>@イベント名.prevent → デフォルト動作の防止</h3>
<a @click.prevent href="http://www.example.com">デフォルト動作を防止</a>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
userName: '',
userAge: '',
},
methods: {
parentClick() {
alert('親要素がクリックされました')
},
childClick(event) {
alert('子要素がクリックされました')
}
}
})
</script>
</body>
</html>
二、v-bindによるスタイル制御の強化 - class操作
1.概要
スタイル制御を容易にするため、Vueはv-bindの構文を拡張し、classクラス名とstyleインラインスタイルの制御が可能です。
2.構文
<div :class = "オブジェクト/配列">これはdivです</div>
3.オブジェクト構文
classがオブジェクトとして動的にバインドされている場合、キーがクラス名、値が真偽値です。値がtrueの場合、そのクラスが適用され、falseの場合は適用されません。
<div class="box" :class="{ クラス名1: 真偽値, クラス名2: 真偽値 }"></div>
使用シナリオ: 1つのクラス名を切り替える場合
4.配列構文
classが配列として動的にバインドされている場合 → 配列内のすべてのクラスが要素に追加され、本質的にclassのリストです。
<div class="box" :class="[ 'クラス名1', 'クラス名2', 'クラス名3' ]"></div>
使用シナリオ: クラスを一括で追加または削除する場合
5.コード例
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>class操作のデモ</title>
<style>
.container {
width: 200px;
height: 200px;
border: 3px solid #000;
font-size: 30px;
margin-top: 10px;
display: flex;
justify-content: center;
align-items: center;
}
.pink {
background-color: rgb(160, 222, 150);
}
.large {
width: 300px;
height: 300px;
}
</style>
</head>
<body>
<div id="app">
<!-- オブジェクトによるバインド -->
<div class="container" :class="{container: true, pink: true, large: true}">Vue</div>
<!-- 配列によるバインド -->
<div class="container" :class="['container', 'pink', 'large']">Vue</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
}
})
</script>
</body>
</html>
三、ケーススタディ - タブ切り替えナビゲーションのハイライト
要件: タブ項目をクリックすると、そのタブ項目がハイライト表示されます。
コード:
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>タブ切り替えナビゲーション</title>
<style>
* {
margin: 0;
padding: 0;
}
ul {
display: flex;
border-bottom: 2px solid #e01222;
padding: 0 10px;
}
li {
width: 100px;
height: 50px;
line-height: 50px;
list-style: none;
text-align: center;
}
li a {
display: block;
text-decoration: none;
font-weight: bold;
color: #333333;
}
li a.active {
background-color: #e01222;
color: #fff;
}
</style>
</head>
<body>
<div id="app">
- [{{item.label}}](#)
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
currentTab: 0, // ハイライトを記録
menuItems: [
{ id: 1, label: 'セール商品' },
{ id: 2, label: 'デイリーセール' },
{ id: 3, label: 'カテゴリーセール' }
]
}
})
</script>
</body>
</html>
四、v-bindによるスタイル制御の強化 - style操作
構文: :style="スタイルオブジェクト"
<div class="box" :style="{ CSSプロパティ名1: CSSプロパティ値, CSSプロパティ名2: CSSプロパティ値 }"></div>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>style操作のデモ</title>
<style>
.box {
width: 200px;
height: 200px;
background-color: rgb(187, 150, 156);
margin: 20px;
}
</style>
</head>
<body>
<div id="app">
<div class="box" :style="{ width: '400px', height: '400px', backgroundColor: '#748d71'}"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
}
})
</script>
</body>
</html>
プログレスバーのケーススタディ(スタイルの動的制御)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>プログレスバーのデモ</title>
<style>
.progress-container {
height: 25px;
width: 400px;
border-radius: 15px;
background-color: #272425;
border: 3px solid #272425;
box-sizing: border-box;
margin-bottom: 30px;
}
.progress-bar {
width: 50%;
height: 20px;
border-radius: 10px;
text-align: right;
position: relative;
background-color: #409eff;
background-size: 20px 20px;
box-sizing: border-box;
transition: all 1s;
}
.progress-bar span {
position: absolute;
right: -20px;
bottom: -25px;
}
</style>
</head>
<body>
<div id="app">
<!-- プログレスバーのコンテナ -->
<div class="progress-container">
<!-- プログレスバーの内側部分、幅を動的にバインド -->
<div class="progress-bar" :style="{ width: progressPercent + '%'}">
<span>{{ progressPercent }}%</span> <!-- 現在のパーセンテージを表示 -->
</div>
</div>
<!-- 異なるパーセンテージを設定するための4つのボタン -->
<button @click="progressPercent = 25">25%に設定</button>
<button @click="progressPercent = 50">50%に設定</button>
<button @click="progressPercent = 75">75%に設定</button>
<button @click="progressPercent = 100">100%に設定</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
progressPercent: 5 // progressPercentデータプロパティを初期化、デフォルト値は5%
}
})
</script>
</body>
</html>
五、v-modelのその他のフォーム要素での使用
一般的なフォーム要素はすべてv-modelでバインドでき、値の取得または設定を迅速に行えます。
これはコントロールのタイプに基づいて、要素を更新するための適切な方法を自動的に選択します。
テキスト入力框 input:text ——> value テキストエリア textarea ——> value チェックボックス input:checkbox ——> checked ラジオボタン input:radio ——> checked セレクトボックス select ——> value …
コード例:
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>フォーム要素のv-model使用例</title>
<style>
textarea {
display: block;
width: 240px;
height: 100px;
margin: 10px 0;
}
</style>
</head>
<body>
<div id="app">
<h3>学習サイト登録フォーム</h3>
お名前:
<input type="text" v-model="userName">
<br><br>
独身ですか:
<input type="checkbox" v-model="isSingle">
<br><br>
<!--
前提知識:
1. name: ラジオボタンにname属性を追加するとグループ化できる → 同じグループ内では互いに排他的になる
2. value: ラジオボタンにvalue属性を追加し、バックエンドに送信するデータを設定
Vueとの連携 → v-model
-->
性別:
<input v-model="gender" type="radio" name="gender" value="1">男性
<input v-model="gender" type="radio" name="gender" value="2">女性
<br><br>
<!--
前提知識:
1. optionにvalue値を設定し、バックエンドに送信
2. selectのvalue値が選択されたoptionのvalue値と関連付けられる
Vueとの連携 → v-model
-->
所在城市:
<select v-model="cityId">
<option value="101">東京</option>
<option value="102">大阪</option>
<option value="103">名古屋</option>
<option value="104">福岡</option>
</select>
<br><br>
自己紹介:
<textarea v-model="selfIntro"></textarea>
<button>今すぐ登録</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
userName: '',
isSingle: false,
gender:'2',
cityId: '102',
selfIntro: ""
}
})
</script>
</body>
</html>
六、算出プロパティ(Computed)
1.概念
既存のデータに基づいて計算された新しいプロパティです。依存するデータが変化すると、自動的に再計算されます。値を計算するコードをカプセル化できます。
2.構文
- computed設定項目で宣言され、1つの算出プロパティが1つの関数に対応
- 通常のプロパティと同じように
{{ 算出プロパティ名 }}として使用
3.注意点
- computed設定項目はdata設定項目と同レベルです
- computed内の算出プロパティは関数の書き方ですが、依然としてプロパティです
- computed内の算出プロパティはdata内のプロパティと同名にできません
- computed内の算出プロパティはdata内のプロパティと同じように使用します
- computed内の算出プロパティ内のthisは依然としてVueインスタンスを指します
4.コード例
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>算出プロパティのデモ</title>
<style>
table {
border: 1px solid #000;
text-align: center;
width: 240px;
}
th,
td {
border: 1px solid #000;
}
h3 {
position: relative;
}
</style>
</head>
<body>
<div id="app">
<h3>ギフトリスト</h3>
| 名前 | 数量 |
|---|---|
| {{ item.name }} | {{ item.num }}個 |
<!-- 目標: 合計を計算し、ギフトの総数を求める -->
<p>ギフトの総数:{{ totalGiftCount }} 個</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
// 既存のデータ
giftList: [
{ id: 1, name: 'バスケットボール', num: 1 },
{ id: 2, name: 'おもちゃ', num: 2 },
{ id: 3, name: '鉛筆', num: 5 },
]
},
computed: {
totalGiftCount () {
// 既存のデータに基づいて、計算ロジックを記述
// 算出プロパティ関数内では、thisで直接appインスタンスにアクセスできる
return this.giftList.reduce((sum, item) => sum + item.num, 0)
}
}
})
</script>
</body>
</html>
七、算出プロパティ(Computed) メソッド(Methods)との比較
1.算出プロパティ
役割: データの処理をカプセル化し、結果を求める
構文:
- computed設定項目に記述
- プロパティとして直接使用
- JSで算出プロパティを使用:
this.算出プロパティ名 - テンプレートで算出プロパティを使用:
{{算出プロパティ名}}
2.メソッド
役割: Vueインスタンスにメソッドを提供し、ビジネスロジックの処理に使用する
構文:
- methods設定項目に記述
- メソッドとして呼び出す
- JSで呼び出す:
this.メソッド名() - テンプレートで呼び出す:
{{メソッド名()}}または@イベント名="メソッド名"
3.算出プロパティの利点
- キャッシュ特性(パフォーマンス向上)
算出プロパティは計算結果をキャッシュし、再利用時は直接キャッシュから読み取ります。依存項目が変化すると、自動的に再計算 → 再度キャッシュします
- メソッドにはキャッシュ特性がない
- コード比較
比較コード:
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>算出プロパティとメソッドの比較</title>
<style>
table {
border: 1px solid #000;
text-align: center;
width: 300px;
}
th,
td {
border: 1px solid #000;
}
h3 {
position: relative;
}
span {
position: absolute;
left: 145px;
top: -4px;
width: 16px;
height: 16px;
color: white;
font-size: 12px;
text-align: center;
border-radius: 50%;
background-color: #e63f32;
}
</style>
</head>
<body>
<div id="app">
<h3>ギフトリスト🛒<span>{{ calculateTotal() }}</span></h3>
<h3>ギフトリスト🛒<span>{{ calculateTotal() }}</span></h3>
<h3>ギフトリスト🛒<span>{{ calculateTotal() }}</span></h3>
<h3>ギフトリスト🛒<span>{{ calculateTotal() }}</span></h3>
<h3>ギフトリスト🛒<span>{{ calculateTotal() }}</span></h3>
| 名前 | 数量 |
|---|---|
| {{ item.name }} | {{ item.num }}個 |
<p>ギフトの総数:{{ calculateTotal() }} 個</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
// 既存のデータ
giftList: [
{ id: 1, name: 'バスケットボール', num: 3 },
{ id: 2, name: 'おもちゃ', num: 2 },
{ id: 3, name: '鉛筆', num: 5 },
]
},
methods: {
calculateTotal() {
console.log("メソッドが実行されました")
let total = this.giftList.reduce((sum, item) => sum + item.num, 0)
return total
}
},
computed: {
// 算出プロパティ: キャッシュ特性があり、一度計算された結果はキャッシュされる
// 次にデータを読み取る際は、直接キャッシュから読み取るため、メソッドよりパフォーマンスが高い
totalGiftCount() {
console.log("算出プロパティが実行されました")
let total = this.giftList.reduce((sum, item) => sum + item.num, 0)
return total
}
}
})
</script>
</body>
</html>
メソッドを使用した場合の結果:
これは、メソッドを使用するたびにデータを再計算する必要があることを示しており、パフォーマンスが低いです。
算出プロパティを使用した場合の結果:
これは、算出プロパティが最初に結果を計算した後、データをキャッシュすることを示しています。次にデータを読み取る際は、直接キャッシュから読み取ります。計算結果が変更されない限り、常にキャッシュからデータを読み取るため、パフォーマンスが非常に高いです。計算結果が変更された場合、キャッシュから古い結果を読み取るのではなく、算出プロパティで再計算し、再度キャッシュします。これにより、計算結果が変更されない限り、常にキャッシュからデータを読み取ることができます。
算出プロパティのまとめ
1.算出プロパティはキャッシュ特性がありますが、メソッドにはキャッシュがありません
2.1つの結果が他の複数の値に依存する場合、算出プロパティの使用をお勧めします
3.ビジネスロジックを処理する場合、例えばイベントの処理関数など、メソッドの使用をお勧めします
八、算出プロパティの完全な構文
算出プロパティもプロパティであるため、算出プロパティは読み取り専用ではなく、変更も可能です。
- 算出プロパティのデフォルトの省略記法は、読み取り専用で、変更はできません
computed: {
算出プロパティ名 () {
計算ロジック
return 結果
}
}
- 変更する場合は、算出プロパティの完全な構文を記述する必要があります
computed: {
算出プロパティ名: {
get () {
計算ロジック
return 結果
},
set (設定する値) {
変更ロジック
}
}
}
コード例
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>算出プロパティの完全な構文</title>
</head>
<body>
<div id="app">
苗字:<input type="text" v-model="firstName"> +
名前:<input type="text" v-model="lastName"> =
<span>{{ fullName }}</span><br><br>
<button @click="changeName">改名カード</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
firstName: '田中',
lastName: '太郎'
},
computed: {
// 省略記法は取得のみで、設定ロジックを構成していない
// fullName() {
// return this.firstName + this.lastName
// }
// 完全な構文で、取得と設定のロジックを構成
fullName: {
// (1)fullName算出プロパティが取得・評価される場合、getが実行される(キャッシュあり)
// 初期値を返し、これがfullNameの初期値となる
get() {
return this.firstName + this.lastName
},
// setメソッドを構成し、fullName算出プロパティが値に設定される場合、setが実行される
// パラメータvalueはfullNameに設定された値
set(value) {
this.firstName = value.slice(0, 1)
this.lastName = value.slice(1)
}
}
},
methods: {
changeName() {
this.fullName = '佐藤花子'
}
}
})
</script>
</body>
</html>
九、ウォッチャー(監視器)
1.役割
データの変化を監視し、ビジネスロジックや非同期操作を実行する
2.構文
watchもdataと同レベルの設定項目で宣言します
簡潔な書き方: 単純な型のデータを直接監視
data: {
words: 'リンゴ',
obj: {
words: 'リンゴ'
}
},
watch: {
// このメソッドはデータが変化した場合にトリガーされ、実行される
データプロパティ名 (newValue, oldValue) {
ビジネスロジックや非同期操作
},
'オブジェクト.プロパティ名' (newValue, oldValue) {
ビジネスロジックや非同期操作
}
}
翻訳器のシミュレーション(簡潔な書き方)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>翻訳器のデモ</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 18px;
}
#app {
padding: 10px 20px;
}
.query {
margin: 10px 0;
}
.box {
display: flex;
}
textarea {
width: 300px;
height: 160px;
font-size: 18px;
border: 1px solid #dedede;
outline: none;
resize: none;
padding: 10px;
}
textarea:hover {
border: 1px solid #1589f5;
}
.transbox {
width: 300px;
height: 160px;
background-color: #f0f0f0;
padding: 10px;
border: none;
}
.tip-box {
width: 300px;
height: 25px;
line-height: 25px;
display: flex;
}
.tip-box span {
flex: 1;
text-align: center;
}
.query span {
font-size: 18px;
}
.input-wrap {
position: relative;
}
.input-wrap span {
position: absolute;
right: 15px;
bottom: 15px;
font-size: 12px;
}
.input-wrap i {
font-size: 20px;
font-style: normal;
}
</style>
</head>
<body>
<div id="app">
<!-- 条件選択ボックス -->
<div class="query">
<span>翻訳先の言語:</span>
<select>
<option value="italy">イタリア語</option>
<option value="english">英語</option>
<option value="german">ドイツ語</option>
</select>
</div>
<!-- 翻訳ボックス -->
<div class="box">
<div class="input-wrap">
<textarea v-model="inputText.words"></textarea>
<span><i>⌨️</i>ドキュメント翻訳</span>
</div>
<div class="output-wrap">
<div class="transbox">{{ translationResult }}</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
// APIエンドポイント: https://applet-base-api-t.itheima.net/api/translate
// リクエスト方法: get
// リクエストパラメータ:
// (1)words: 翻訳するテキスト(必須)
// (2)lang: 翻訳先の言語(オプション)デフォルト-イタリア語
// -----------------------------------------------
new Vue({
el: '#app',
data: {
//words: ''
inputText: {
words: ''
},
translationResult: '', // 翻訳結果
// timer: null // タイマーID
},
// 詳細な説明:(1) watch構文 (2) 具体的なビジネス実装
watch: {
// このメソッドはデータが変化した場合に呼び出され実行される
// newValue新値, oldValue旧値(通常は使用しない)
// words (newValue) {
// console.log('変化しました', newValue)
// }
'inputText.words'(newValue) {
// console.log('変化しました', newValue)
// デバウンス: 遅延実行 → 何をするかは少し待つ、遅延させ、一定期間内に再度トリガーされなければ実行
clearTimeout(this.timer)
this.timer = setTimeout(async () => {
const res = await axios({
url: 'https://applet-base-api-t.itheima.net/api/translate',
params: {
words: newValue
}
})
if (this.inputText.words === '') {
this.translationResult = ''
} else {
this.translationResult = res.data.data
}
console.log(res.data.data)
}, 300)
}
}
})
</script>
</body>
</html>
完全な書き方 —>追加の設定項目を追加
deep: true
- 用途: 複雑な型(オブジェクトや配列)を深く監視する
- 例: オブジェクトの内部プロパティや配列の内部要素の変化を監視する必要がある場合に使用
- 説明:
deep: trueを使用しない場合、オブジェクトや配列自体の変化のみが監視され、内部プロパティや要素の変化は監視されません
watch: {
user: {
handler(newValue, oldValue) {
// userオブジェクトのいずれかのプロパティが変化した場合に実行
},
deep: true
}
}
immediate: true
- 用途: インスタンス化時に即座にコールバックを実行する
- 例: コンポーネントの読み込み時にすぐにロジックを実行する必要がある場合に使用
- 説明: デフォルトでは、
watchウォッチャーは監視されているデータが変化した場合にのみ実行されます。immediate: trueを設定すると、ウォッチャーがインスタンス化された際に即座にコールバックが一度実行されます
watch: {
someData: {
handler(newValue, oldValue) {
// 即座に一度実行し、その後someDataが変化した場合に再度実行
},
immediate: true
}
}
例
この例では、userオブジェクトのいずれかのプロパティが変化するたびにhandler関数がトリガーされ、コンポーネントの読み込み時に即座にhandler関数が一度実行されます
export default {
data() {
return {
user: {
name: '',
age: 0
}
}
},
watch: {
user: {
handler(newValue) {
console.log('Userデータが変更されました:', newValue);
},
deep: true,
immediate: true
}
}
}
翻訳器のシミュレーション(完全な書き方)
- テキストボックスに入力すると、右側の翻訳内容がリアルタイムで変化する
- ドロップダウンボックスの言語が変化しても、右側の翻訳内容は依然としてリアルタイムで変化する
- テキストボックスにデフォルト値がある場合は、すぐに翻訳する必要がある
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>翻訳器のデモ(完全な書き方)</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-size: 18px;
}
#app {
padding: 10px 20px;
}
.query {
margin: 10px 0;
}
.box {
display: flex;
}
textarea {
width: 300px;
height: 160px;
font-size: 18px;
border: 1px solid #dedede;
outline: none;
resize: none;
padding: 10px;
}
textarea:hover {
border: 1px solid #1589f5;
}
.transbox {
width: 300px;
height: 160px;
background-color: #f0f0f0;
padding: 10px;
border: none;
}
.tip-box {
width: 300px;
height: 25px;
line-height: 25px;
display: flex;
}
.tip-box span {
flex: 1;
text-align: center;
}
.query span {
font-size: 18px;
}
.input-wrap {
position: relative;
}
.input-wrap span {
position: absolute;
right: 15px;
bottom: 15px;
font-size: 12px;
}
.input-wrap i {
font-size: 20px;
font-style: normal;
}
</style>
</head>
<body>
<div id="app">
<!-- 条件選択ボックス -->
<div class="query">
<span>翻訳先の言語:</span>
<select>
<option value="italy">イタリア語</option>
<option value="english">英語</option>
<option value="german">ドイツ語</option>
</select>
</div>
<!-- 翻訳ボックス -->
<div class="box">
<div class="input-wrap">
<textarea v-model="translationData.words"></textarea>
<span><i>⌨️</i>ドキュメント翻訳</span>
</div>
<div class="output-wrap">
<div class="transbox">{{ translationResult }}</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
translationData: {
words: 'こんにちは',
lang: 'italy'
},
translationResult: '', // 翻訳結果
},
watch: {
translationData: {
deep: true, // 深く監視
immediate: true, // 即座に実行、ページに入るとhandlerが即座に一度実行される
handler(newValue) {
clearTimeout(this.timer)
this.timer = setTimeout(async () => {
const res = await axios({
url: 'https://applet-base-api-t.itheima.net/api/translate',
params: newValue
})
if (this.translationData.words === '') {
this.translationResult = ''
} else {
this.translationResult = res.data.data
}
console.log(res.data.data)
}, 300)
}
}
}
})
</script>
</body>
</html>