最近都在学习前端的路上缓慢前进,在了解了 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)