Recently, I have been slowly progressing on the road of learning front-end development. After understanding Vue, I started learning Typescript. Every time I learn something new, I can't help but use it to create something that interests me. I think it's very cooooooooool! 👊
I happened to see Jizhu's map before, and I think it's excellent. Coincidentally, our school doesn't have a related product, only a hand-drawn picture map. After a little thought:
- Considering portability, I decided to use it on mobile devices.
- It should be able to mark the locations of school facilities.
- The bus routes and boarding locations.
- It should have product and school introductions.
- It would be best to see the real scene of the school.
In addition, I have learned Vue before, so I plan to combine it with Vue to write. Let's do it! ✈️
But then, on the first day, I encountered a problem when creating the project.
At first, I installed Vue version 2.x, and the webpack version for creating a new project was 3.6. When using Typescript, it prompted me to upgrade webpack to version 4.x. At first, I didn't think too much about it. I just googled the problems it prompted and how to solve them (programming with search engines). After a quick look, they all involved uninstalling old dependencies and installing new ones, as well as modifying configurations. However, their tutorials were basically different, and the only thing that was the same was that they were all very complicated. I didn't know which one to choose, so I picked one that looked good and started writing according to it. As a result, it failed... Later, I found out that Vue 3.x versions have already started to adapt to Typescript. You can choose whether to use Typescript when creating a project, and it will be automatically configured for you... Ah, this.
Uninstall the old version of Vue!
npm uninstall vue-cli -g
Install the latest version of Vue!
npm install -g @vue/cli
Let's try again, take off! ✈️
Project address: HgMap
Map link: Hua Guang Map
Environment Dependencies#
- vue/cli 4.4.6
- typescript
- element-ui: UI components
- vue-class-component: Class decorator
- vue-property-decorator: Extension based on vue-class-component in the vue organization
- vue2-svg-icon: SVG icon component
- Map resources are from the AMap API
Note: Since vue-cli 4 does not come with vue.config.js by default, you need to create and configure it in the root directory yourself, otherwise the project packaging will not be able to find static resources.
Using Vue and Typescript#
Prerequisites#
Add the lang="ts" attribute to the script tag.
<script lang="ts">
···
</script>
Creating a component#
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
@Component
export default class Test extends Vue {
}
Importing a component#
import Mapmenu from '@/components/Mapmenu.vue'
@Component({
components: {
Mapmenu
}
})
Data object#
For simple types like boolean or string, Typescript will automatically recognize them without specifying the type. Otherwise, it will give me an error when running...
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
export default class Map extends Vue {
map: any = null
dialog = false
name = "MAGREN"
}
Method#
Methods can be written directly in the export default section without using commas, and the return type needs to be specified.
<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
// School introduction
toPageSchoolInfo(): void{
this.$router.push({
path:'/schoolinfo'
})
}
………………
}
Prop and Emit for passing parameters between parent and child components#
Parent component
='map' means passing the map parameter from the parent component to the child component and naming it map.
@show-dialog="handleChildValue" means handling the value passed from the child component in the handleChildValue method.
<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: value passed from the child component
this.dialog = val;
}
}
Child component
To access the parameter passed from the parent component, simply use this.xxx.
To pass parameters to the parent component, simply call the method in the @Emit annotation.
<script lang="ts">
// Import Prop and 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
// Receive value passed from the parent component
@Prop()
private map: any
// Pass value to the parent component
@Emit()
private showDialog(){
return this.show
}
}
Loading and Using AMap#
Loading AMap#
Encapsulate the map and load it asynchronously using a Promise. TypeScript checks the window type during compilation and does not allow direct calls to window.xx. Changing it to any type allows it to be used. Check if it already exists before loading.
export default function MapLoader(): Promise<void>{
return new Promise((resolve, reject) => {
const win: any = window
if (win.AMap) {
resolve(win.AMap)
} else {
const url='AMap API URL'
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)
}
})
}
Call it where needed
<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
// Initialize the map
async initAMap(): Promise<void> {
try {
const res: any = await AMap();
this.map = new res.Map("container", { // Load it into the div with the id "container"
viewMode:'3D', // Map mode, only 2D effect on mobile
resizeEnable: true, // Monitor changes in the size of the map container
zoom: 17, // Initial map zoom level
center: [113.172847,23.43399], // Initial map center point
pitch:40, // Map pitch angle, valid range: 0 degrees to 83 degrees
buildingAnimation:true, // 3D map animation
});
this.personOptions(this.map,true)
}catch (err) {
console.error(err);
}
}
mounted() {
this.initAMap();
}
}
</script>
Adding markers to the map#
const win: any = window
const marker = new win.AMap.Marker({
position: new win.AMap.LngLat(113.171688,23.433279), // Marker coordinates
})
Adding text above the marker:
marker.setLabel({ // The label is displayed in the top left corner with a blue border and white background by default
offset: new win.AMap.Pixel(0, -3), // Set the offset of the text label
content:"Commercial Street", // Set the content of the text label
direction: 'top' // Set the direction of the text label
});
Modify the style:
At this time, the css tag cannot have the scoped attribute, otherwise it will not take effect. This issue is related to the scope of css.
.amap-marker-label{
padding: 5px;
border-radius: 3px;
border-color: ##54B7E7;
border-width: 0px;
color:##54B7E7;
}
Finally, call the add method to add:
this.map.add(marker)