Magren

Magren

Idealist & Garbage maker 🛸
twitter
jike

HGマップについて

最近フロントエンドの道をゆっくり進んでいて、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

もう一度やってみる、出発!✈️

プロジェクトのアドレス:HgMap
地図のリンク:華広地図

環境依存#

  • 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
 // methods
 //学校紹介
 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)
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。