最近都在學習前端的路上緩慢前進,在了解了 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 組織裡 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">
// @ is an alias to /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>
給地圖添加 marker#
const win: any = window
const marker = new win.AMap.Marker({
position: new win.AMap.LngLat(113.171688,23.433279), //marker的坐標
})
在 marker 上方添加文本:
marker.setLabel({ //label默認藍框白底左上角顯示l
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)