最近フロントエンドの学習をゆっくり進めています。Vue を理解した後、TypeScript の学習を始めました。新しいことを学ぶたびに、自分が興味のあるものを作りたくなり、こうするのがとても Coooooooooooool だと思っています!👊
以前、偶然に吉珠の地図を見かけて、非常に優れていると感じました。たまたま私たちの学校には関連する製品がなく、ただ描かれた画像の地図しかありませんでした。少し考えた結果、
- 携帯性を考慮して、モバイル端末で使用することに決めました。
- 学校の施設の場所を示す必要があります。
- シャトルバスのルートと乗降場所。
- 製品の紹介と学校の紹介が必要です。
- 学校の実景が見えると良いです。
以前に Vue を学んだこともあり、Vue を使って書くことに決めました。やると決めたらすぐに行動!✈️
そして、初日はプロジェクトの作成でつまずきました。
最初にインストールした Vue のバージョンは 2.x で、新しいプロジェクトの webpack バージョンは 3.6 でした。TypeScript を使用する際に webpack を 4.x バージョンにアップグレードする必要があると表示されました。最初はあまり考えず、表示された問題を Google で検索して解決策を探しました(検索エンジンに頼るプログラミング)。ざっと見たところ、古い依存関係をアンインストールして新しい依存関係をインストールし、設定を変更するという内容が多かったですが、彼らのチュートリアルは基本的に異なり、唯一共通していたのはどれも非常に複雑で、どう選べばいいのかわからず、見た目が良さそうなものを選んで書き始めた結果、失敗しました…… その後、Vue3.x バージョンからは TypeScript に対応し始めており、プロジェクト作成時に TypeScript を使用するかどうかを選択でき、自動的に設定されることがわかりました…… ああ、これ。
古いバージョンの Vue をアンインストール!
npm uninstall vue-cli -g
最新バージョンの Vue をインストール!
npm install -g @vue/cli
もう一度やってみて、出発!✈️
環境依存#
- vue/cli 4.4.6
- typescript
- element-ui:UI コンポーネント
- vue-class-component:クラスデコレーター
- vue-property-decorator:vue-class-component を基にした拡張
- vue2-svg-icon:SVG アイコンコンポーネント
- 地図リソースは高徳地図 API から取得
注:vue-cli 4 バージョンには vue.config.js が自動で付属しないため、ルートディレクトリに自分で作成して設定する必要があります。そうしないと、プロジェクトのパッケージング時に静的リソースが見つからなくなります。
Vue と TypeScript の使用#
前提#
script タグに : lang=“ts” を追加
<script lang="ts">
···
</script>
コンポーネントの作成#
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
@Component
export default class Test extends Vue {
}
コンポーネントのインポート#
import Mapmenu from '@/components/Mapmenu.vue'
@Component({
components: {
Mapmenu
}
})
data オブジェクト#
boolean や string などの単純な型は TypeScript が自動で認識するため、型を明示する必要はありません。そうしないと、実行時にエラーが出ます……
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
export default class Map extends Vue {
map: any = null
dialog = false
name = "MAGREN"
}
method メソッド#
カンマで区切る必要はなく、export default 内に直接書き、戻り値の型を明示する必要があります。
<script lang="ts">
import { Component,Vue,Prop,Emit } from 'vue-property-decorator';
import markers from '@/config/markers.ts'
@Component
export default class Mapmenu extends Vue {
show = true
// メソッド
// 学校紹介
toPageSchoolInfo(): void{
this.$router.push({
path:'/schoolinfo'
})
}
………………
}
Prop および Emit を使用した親子コンポーネント間のパラメータ伝達#
親コンポーネント
= 'map’は親コンポーネントの map パラメータを子コンポーネントに渡し、map という名前を付けます。
@show-dialog=“handleChildValue” は子コンポーネントから送られた値を handleChildValue メソッドで処理します。
<template>
<Mapmenu :map='map' @show-dialog="handleChildValue"></Mapmenu>
</template>
<script lang="ts">
// @は/srcへのエイリアスです
import AMap from '@/config/amap.ts'
import Mapmenu from '@/components/Mapmenu.vue'
import { Component,Vue } from 'vue-property-decorator';
@Component({
components: {
Mapmenu
}
})
export default class Map extends Vue {
dialog = false
……
private handleChildValue(val: boolean) {
// val: 子コンポーネントから送られた値
this.dialog = val;
}
}
子コンポーネント
親コンポーネントから渡されたパラメータは this.xxx で直接使用します。
親コンポーネントにパラメータを渡すには、@Emit デコレーター内のメソッドを呼び出します。
<script lang="ts">
// PropとEmitをインポート
import { Component,Vue,Prop,Emit } from 'vue-property-decorator';
import markers from '@/config/markers.ts'
@Component
export default class Mapmenu extends Vue {
show = true
// 親コンポーネントから送られた値を受け取る
@Prop()
private map: any
// 親コンポーネントに値を送る
@Emit()
private showDialog(){
return this.show
}
}
高徳地図の読み込みと使用#
高徳地図の読み込み#
地図をラップし、Promise を通じて非同期で読み込みます。TypeScript はコンパイル時に window 型をチェックし、直接 window.xx を呼び出すことを許可しません。any 型に変更すれば使用できます。読み込む前に、すでに存在するかどうかを確認します。
export default function MapLoader(): Promise<void>{
return new Promise((resolve, reject) => {
const win: any = window
if (win.AMap) {
resolve(win.AMap)
} else {
const url='高徳地図api'
const script: HTMLScriptElement = document.createElement('script')
script.charset = 'utf-8'
script.src = url
script.onerror = reject
document.head.appendChild(script)
}
win.onLoad = () => {
resolve(win.AMap)
}
})
}
必要な場所で呼び出します。
<template>
<div id="map">
<div id="container">
</div>
</div>
</template>
<script lang="ts">
import AMap from '@/config/amap.ts'
import { Component,Vue } from 'vue-property-decorator';
export default class Map extends Vue {
map: any = null
// 地図を初期化
async initAMap(): Promise<void> {
try {
const res: any = await AMap();
this.map = new res.Map("container", { // idがcontainerのdivに装載
viewMode:'3D', // 地図モード、モバイルでは2D効果のみ
resizeEnable: true, // 地図コンテナのサイズ変化を監視するか
zoom: 17, // 地図の初期レベル
center: [113.172847,23.43399], // 地図の初期中心点
pitch:40, // 地図の俯瞰角度、有効範囲は0度-83度
buildingAnimation:true, // 3D地図表示アニメーション
});
this.personOptions(this.map,true)
}catch (err) {
console.error(err);
}
}
mounted() {
this.initAMap();
}
}
</script>
地図にマーカーを追加#
const win: any = window
const marker = new win.AMap.Marker({
position: new win.AMap.LngLat(113.171688,23.433279), // マーカーの座標
})
マーカーの上にテキストを追加:
marker.setLabel({ // labelはデフォルトで青い枠と白い背景で左上に表示される
offset: new win.AMap.Pixel(0, -3), // テキストラベルのオフセットを設定
content:"商業街", // テキストラベルの内容を設定
direction: 'top' // テキストラベルの方向を設定
});
スタイルを変更:
この時、css タグに scoped を付けてはいけません。そうしないと効果がありません。この問題は css のスコープに関わります。
.amap-marker-label{
padding: 5px;
border-radius: 3px;
border-color: ##54B7E7;
border-width: 0px;
color:##54B7E7;
}
最後に add メソッドを呼び出して追加します:
this.map.add(marker)