最近一直在作移動端微信公衆號項目的開發,也是我首次用vue來開發移動端項目,前期積累的移動端開發經驗較少。通過這個項目的鍛鍊,加深了對vue相關知識點的理解和運用,同時,在項目中所涉及到的微信api(微信分享,微信支付),百度地圖api(如何實例化地圖,給地圖添加自定義覆蓋物,給地圖添加自定義標註,對地圖進行縮放,拖拽等)的相關使用,開闊了本身的知識眼界;現將我開發過程當中積累的相關經驗與你們進行分享,但願和你們一塊兒學習和進步....javascript
vux:Vue 移動端 UI 組件庫的使用;php
vue-lazyload :一個簡單易用的 Vue 圖片延遲加載插件;css
vuex:vue狀態管理工具詳細入門;html
async/await:異步神器來封裝接口請求文件fetch.js前端
vue 項目中的迭代判斷技巧;vue
vue 項目中經常使用的圖片引入方式;java
微信api在vue項目中的使用:webpack
vue2實現微信分享坑點和經驗 ;git
vue2實現微信支付坑點和經驗;es6
百度地圖api在vue項目中的使用:
vue2.0項目中如何使用百度地圖api
vue2如何給地圖添加房源覆蓋物;
如何給地圖添加自定義定位控件並更換控件的圖標;
如何給地圖添加自定義當前位置定位標註
幾個經常使用的api(地圖縮放,拖拽,獲取當前位置)等功能的實現;
vux介紹:詳細請參見官方文檔。
因爲是作微信公衆號移動端項目,咱們對比了幾個vuejs的移動端UI庫,知道vux是基於WeUI和Vue(2.x)開發的移動端UI組件庫,主要服務於微信頁面;雖然它屬於我的維護,體驗上須要一些改進。但項目中幾個組件的使用,大大提高了開發效率。
使用方法以下:
npm install vux --save
vux2必須配合vux-loader使用, 請在build/webpack.base.conf.js裏參照以下代碼進行配置:vux2必須配合vux-loader使用, 請在build/webpack.base.conf.js裏參照以下代碼進行配置:
const vuxLoader = require('vux-loader') const webpackConfig = originalConfig // 原來的 module.exports 代碼賦值給變量 webpackConfig module.exports = vuxLoader.merge(webpackConfig, { plugins: ['vux-ui'] })
若是你要使用的組件只是在當前頁面中使用,咱們能夠只在當前頁面中引入便可。若是在不少頁面中都有使用,能夠在main.js中以全局方式引用。使用組件方法以下:
<template> <swiper auto loop :interval="interval" :duration="duration" id="swiper-banner" class="swiper-banner" :height="height"> <swiper-item class="swiper-demo-img" v-for="(item, index) in bannerList" :key="index"> <img :src="item.img"> </swiper-item> </swiper> </template> <script> import { Swiper, SwiperItem } from "vux"; export default { name: "swiper", data() { interval:4000,// 輪播停留時間 duration:300// 切換動畫時間 height:"10.19rem", // 高度值 bannerList:[ {img: 'https://static.vux.li/demo/1.jpg',title: '送你一朵fua'}, {img: 'https://static.vux.li/demo/5.jpg',title: '小花'} ] } } </script>
屬性auto,默認爲false,表示是否自動輪播;屬性loop,默認爲false,表示是否循環;
官方網址:vue-lazyload
介紹:
vue-lazyload主要應用於圖片延遲加載。包含以下的特色:
理解圖片延遲加載:
當某個網頁中呈現的圖片較多時,因爲網絡等緣由,訪問該網頁時,全部的圖片不會立馬所有進行顯示出來,會出現必定的網絡延遲加載的現象,影響用戶體驗;但咱們能夠vue-lazyload插件來實如今圖片加載的過程當中,先顯示出默認的加載圖片,直到圖片徹底顯示,默認圖片消失,這樣就會大大的提高用戶體驗。
使用方法以下:
一、經過npm安裝
npm install vue-lazyload -s
二、在main.js中進行引用
import Vue from 'vue' import App from './App.vue' import VueLazyload from 'vue-lazyload' Vue.use(VueLazyload, { preLoad: 1.3, // 預壓高度的比例 error: '../assets/img/no-pic.png', // 圖像的加載失敗時 顯示的error圖標 loading: '../assets/imgLoading.png', // 圖像正常加載時 顯示的loading圖標 attempt: 1 // 圖像嘗試加載 次數 })
三、在組件中使用
<img v-lazy="item.picUrl" alt="">
四、實現效果之後,還能夠根據API進行功能擴展。
相應的參數可參考官方API進行設置。
五、vue-lazyLoad文件整理,請參照:vue2-plugs-demo項目中src/components/LazyLoad/index.vue 和 src/main.js部分;;
詳細介紹請參見官方網站。Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
什麼狀況下我應該使用 Vuex?
若是您須要構建一箇中大型單頁應用,您極可能會考慮如何更好地在組件外部管理狀態,Vuex 將會成爲天然而然的選擇。
使用方法:
npm install vuex --save
import Vuex from "vuex"; Vue.use(Vuex);
state:存儲狀態。也就是變量;
getters:派生狀態。也就是set、get中的get,有兩個可選參數:state、getters分別能夠獲取state中的變量和其餘的getters。外部調用方式:store.getters.personInfo()。就和vue的computed差很少;
mutations:提交狀態修改。也就是set、get中的set,這是vuex中惟一修改state的方式,但不支持異步操做。第一個參數默認是state。外部調用方式:store.commit('SET_AGE', 18)。和vue中的methods相似。
actions:和mutations相似。不過actions支持異步操做。第一個參數默認是和store具備相同參數屬性的對象。外部調用方式:store.dispatch('nameAsyn')。
modules:store的子模塊,內容就至關因而store的一個實例。調用方式和前面介紹的類似,只是要加上當前子模塊名,如:store.a.getters.xxx()。
通常來說,咱們都會採用vue-cli來進行實際的開發,在vue-cli中,開發和調用方式稍微不一樣。
├── index.html ├── main.js ├── components └── store ├── index.js # 咱們組裝模塊並導出 store 的地方 ├── state.js # 跟級別的 state ├── getters.js # 跟級別的 getter ├── mutation-types.js # 根級別的mutations名稱(官方推薦mutions方法名使用大寫) ├── mutations.js # 根級別的 mutation ├── actions.js # 根級別的 action └── modules ├── index.js # 模塊集合 ├── m1.js # 模塊1 ├── m2.js # 模塊2
state.js示例:
const state = { name: 'weish', age: 22 }; export default state;
getters.js示例(咱們通常使用getters來獲取state的狀態,而不是直接使用state):
export const name = (state) => { return state.name; } export const age = (state) => { return state.age } export const other = (state) => { return `My name is ${state.name}, I am ${state.age}.`; }
mutation-type.js示例(咱們會將全部mutations的函數名放在這個文件裏):
export const SET_NAME = 'SET_NAME'; export const SET_AGE = 'SET_AGE';
mutations.js示例:
import * as types from './mutation-type.js'; export default { [types.SET_NAME](state, name) { state.name = name; }, [types.SET_AGE](state, age) { state.age = age; } };
actions.js示例(異步操做、多個commit時):
import * as types from './mutation-type.js'; export default { nameAsyn({commit}, {age, name}) { commit(types.SET_NAME, name); commit(types.SET_AGE, age); } };
modules/m1.js示例,m2同理。(若是不是很複雜的應用,通常來說是不會分模塊的):
export default { state: {}, getters: {}, mutations: {}, actions: {} };
modules/indes.js,將modules文件集中管理,以下:
import m1 from './m1'; import m2 from './m2'; export default { m1, m2 }
index.js示例(組裝vuex):
// 若是項目中,使用的狀態管理操做很是頻繁,能夠將狀態管理的對象進行細分,最後聚集以後集中管理; import vue from 'vue' import vuex from 'vuex' import state from './state' import * as getters from './getters' import mutations from './mutations' import actions from './actions' import modules from './modules' vue.use(vuex) export default new vuex.Store({ state, getters, mutations, actions, modules })
最後將store實例掛載到main.js裏面的vue上去就好了
import store from './store'; new Vue({ el: '#app', store, render: h => h(App) });
在vue組件中使用時,咱們一般會使用mapGetters、mapActions、mapMutations,而後就能夠按照vue調用methods和computed的方式去調用這些變量或函數,示例以下:
import {mapGetters, mapMutations, mapActions} from 'vuex'; /* 只寫組件中的script部分 */ export default { computed: { ...mapGetters([ name, age ]) }, methods: { ...mapMutations({ setName: 'SET_NAME', // 映射 this.setName() 爲 this.$store.commit('SET_NAME') setAge: 'SET_AGE' }), ...mapActions([ nameAsyn // 將 this.nameAsyn() 映射爲 this.$store.dispatch('increment') ]) } };
mapGetters,mapMutations,mapActions的使用,至關與將已經定義好的狀態管理數據(變量,函數)引用到vue對象的computed和methods中,咱們在頁面中,只管使用就行;使用方式,如:
獲取computed中的變量:
this.name; this.age;
獲取methods中的變量:
this.setName(this.name);// 映射爲 `this.$store.commit('setName', this.name)` this.setAge(); this.nameAsyn();
一、若是項目中,使用的狀態管理操做很是頻繁,能夠將狀態管理的對象進行細分,如區分不一樣的對象文件夾(state,getters,mutations,actions,modules),最後聚集以後集中管理;
二、若是項目中使用的狀態管理的變量較少時,能夠採用一個文件進行集中管理;
vuex項目整理,請參照:vue2-plugs-demo項目中src/store 和 src/store2部分;
在先後端分離的項目開發中,前端人員若是要經過接口獲取後端數據時,咱們通常會獨立封裝本身的接口異步請求方法,以便在整個項目中都可以輕鬆的進行引用;
項目中使用async/await 來處理異步請求,封裝的方法(utils/fetch.js)以下:
export default async (url = '', data = {}, type = 'POST', method = 'fetch') => { type = type.toUpperCase() // get請求須要進行url和參數的從新拼接 if (type === 'GET') { let dataStr = '' Object.keys(data).forEach(key => { dataStr += key + '=' + data[key] + '&' }) if (dataStr !== '') { dataStr = dataStr.substr(0, dataStr.lastIndexOf('&')) url = url + '?' + dataStr } } // 若是支持fecth語法(es7語法)而且請求方式爲'fetch' if (window.fetch && method === 'fetch') { let requestConfig = { credentials: 'include', method: type, headers: { 'Accept': 'application/json;charset=UTF-8', 'Content-Type': 'application/json;charset=UTF-8' }, mode: 'cors', cache: 'force-cache' } // 'POST'請求,將相關的請求參數添加到'body'中。 if (type === 'POST') { Object.defineProperty(requestConfig, 'body', { value: JSON.stringify(data) }) } // await fetch,以同步的方式將數據(json形式)進行返回,前端經過變量接收便可; try { const response = await fetch(url, requestConfig) const responseJson = await response.json() return responseJson } catch (error) { throw new Error(error) } } else { // 若是先瀏覽器不支持fetch語法,則用es6中promise()來封裝異步接口請求; return new Promise((resolve, reject) => { let requestObj if (window.XMLHttpRequest) { requestObj = new XMLHttpRequest() } else { let ActiveXObject = window.ActiveXObject requestObj = new ActiveXObject() } let sendData = '' if (type === 'POST') { sendData = JSON.stringify(data) } requestObj.open(type, url, true) requestObj.setRequestHeader('Content-type', 'application/x-www-form-urlencoded') requestObj.send(sendData) requestObj.onreadystatechange = () => { if (requestObj.readyState === 4) { if (requestObj.status === 200) { let obj = requestObj.response if (typeof obj !== 'object') { console.log(obj) obj = JSON.parse(obj) } resolve(obj) } else { reject(requestObj) } } } }) } }
如登陸界面的用到的api,統一管理在login/api/index.js中,以下:
import fetch from "@/utils/fetch"; /** * 登陸 */ export const login = (reqData) => fetch("/v2/cotton/user/app_login", reqData);
api統一管理完成以後,咱們須要在頁面中進行調用,獲取數據,方法以下:
import { getyancode, login } from "./api"; methods: { async login() { // 提交時,作驗證; if (this.checkMobile() && this.checkMsgCode()) { this.loading.show = true; let reqData = { phone: mutils.replaceAllSpace(this.telphone), code: mutils.replaceAllSpace(this.yancode) }; try{ // try{}catch(){}用於處理異常 const res = await login(reqData); if (res.status.code == "200") { console.log('接口請求成功~'); } else { console.log('接口請求失敗~'); } }catch(err){ console.log(err) } } } }
經過異步接口請求,咱們就能夠獲取到相關的數據,開始後續的操做了。
異步接口請求封裝方式分析:
async/ await來發送異步請求,從服務端獲取數據,代碼很簡潔,同時async/await 已經被標準化。
async的用法,它做爲一個關鍵字放到函數前面,用於表示函數是一個異步函數,也就意味着該函數的執行不會阻塞後面代碼的執行。如:
async function timeout() { return 'hello world' } timeout(); console.log('雖然在後面,可是我先執行');
async 函數返回的是一個promise 對象,若是要獲取到promise 返回值,咱們應該用then 方法,如:
async function timeout() { return 'hello world' } timeout().then(result => { console.log(result); }) console.log('雖然在後面,可是我先執行');
執行結果:
雖然在後面,可是我先執行 hello world
async和await結合使用,await表示等待的意思,注意await 關鍵字只能放到async 函數裏面。如今寫一個函數,讓它返回promise 對象,該函數的做用是2s 以後讓數值乘以2。
css // 2s 以後返回雙倍的值 function doubleAfter2seconds(num) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(2 * num) }, 2000); } ) }
如今再寫一個async 函數,從而可使用await 關鍵字, await 後面放置的就是返回promise對象的一個表達式,因此它後面能夠寫上 doubleAfter2seconds 函數的調用。
async function testResult() { let result = await doubleAfter2seconds(30); console.log(result); }
如今調用testResult 函數
testResult(); 結果爲:60
固然咱們在使用async/await來接口請求時,須要進行異常處理。它用的是try/catch 來捕獲異常,把await 放到 try 中進行執行,若有異常,就使用catch 進行處理。
fetch.js文件整理,請參照:vue2-plugs-demo項目中utils/fetch.js 和 src/login部分;
好比咱們有一個列表,咱們但願能顯示咱們當前選中的那一個,如何實現呢?
基本思路是經過$index來判斷是不是當前迭代對象,而後去增減class或者style來實現不一樣的樣式。
<template> <ul> <!-- 方法1 class--> <li v-for="item in list" :class="{'active': $index === activeId}">{{item}}</li> <!-- 方法2 style--> <li v-for="item in list" :style="{backgroundColor: $index === activeId ? 'red' : 'white'}">{{item}}</li> </ul> </template> <script> data () { return { list: ['a', 'b', 'c'], activeId: 0 } } </script>
data () { return { img: require('path/to/your/source') } }
而後在template中:
<img :src="img" />
data () { return { img: require('path/to/your/source') } } <div :style="{backgroundImage: 'url(' + img + ')'}"></div> 或者直接在css中定義 background-image: url('path/to/your/source');
固然要進行微信公衆號開發,前期是要通過用戶註冊並綁定相關的帳號,纔會獲得微信官網給出的相關的權限,才能夠進行後續的開發流程及api的調用,主體步驟請參見微信公衆號技術文檔。我在這裏,只是介紹註冊流程走完以後,如何進行api的調用。
因爲在作微信公衆號vue2.0前端項目開發,根據產品須要,項目中有一些自定義分享的功能和設計;因爲微信自帶的分享是一個比較普通,是以它本身的分享機制,只是對某個頁面進行一般的呈現。自定義分享,就須要咱們調用微信分享api,進行自定義配置。
分享到微信好友和QQ好友,效果如圖:
分享到微信朋友圈,效果如圖:
開發步驟以下:
一、在index.html中引入jweixin-1.2.0.js;
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
二、相關微信api配置文件utils/wx.js,以下:
import fetch from "./fetch"; /** * baseUrl:服務器地址 * shareOosImg:分享默認的圖標 * wechatId:申請成功的wechatId **/ import { baseUrl,shareOosImg,wechatId } from "@/utils/env"; /** * 獲取微信端簽名,時間戳等信息 */ export const getCompactHouseList = (reqData) => fetch("/v2/cotton/user/get_wechat_authorize", reqData); export function setWxConfig(link, title, desc, pic) { let url = window.location.href.split("#")[0]; // 公衆號申請流程走完以後,官方會給給出一個"wechatId",經過這個參數去請求咱們的後臺接口,就會獲得相關已經配置好的信息。 getCompactHouseList({ "wechatId": wechatId, "url": url }).then((res) => { if (res.status.code == 200) { let wxConfigObj = res.result.parment; let myLink = link ? link : ""; let myTitle = title ? title : "小愛科技"; let Mydesc = desc ? desc : "驚喜多多!優惠多多!"; let mypic = pic ? pic : shareOosImg; wxConfig(wxConfigObj, myLink, myTitle, Mydesc, mypic); } }).catch((err) => { console.log(err); }); }; function wxConfig(wxConfigObj, link, title, desc, pic) { // 進行初始化配置。 wx.config({ debug: false, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 appId: wxConfigObj.appid, // 必填,公衆號的惟一標識 timestamp: wxConfigObj.timestamp, // 必填,生成簽名的時間戳 nonceStr: wxConfigObj.noncestr, // 必填,生成簽名的隨機串 signature: wxConfigObj.signature, // 必填,簽名 jsApiList: ["checkJsApi","onMenuShareTimeline", "onMenuShareAppMessage", "onMenuShareQQ","chooseWXPay", "chooseImage" ] // 必填,須要使用的JS接口列表 }); wx.ready(() => { //分享到朋友圈 wx.onMenuShareTimeline({ title: title, // 分享標題 link: link, // 分享連接,該連接域名或路徑必須與當前頁面對應的公衆號JS安全域名一致 imgUrl: pic, // 分享圖標 success: function () { // alert("分享朋友圈成功"); } }); // 分享給微信朋友 wx.onMenuShareAppMessage({ title: title, // 分享標題 desc: desc, // 分享描述 link: link, // 分享連接,該連接域名或路徑必須與當前頁面對應的公衆號JS安全域名一致 imgUrl: pic, // 分享圖標 type: "", // 分享類型,music、video或link,不填默認爲link dataUrl: "", // 若是type是music或video,則要提供數據連接,默認爲空 success: function () { // 用戶點擊了分享後執行的回調函數 //alert("分享朋友成功"); } }); // 分享到QQ wx.onMenuShareQQ({ title: title, // 分享標題 desc: desc, // 分享描述 link: link, // 分享連接 imgUrl: pic, // 分享圖標 success: function () { // 用戶確認分享後執行的回調函數 }, cancel: function () { // 用戶取消分享後執行的回調函數 } }); wx.checkJsApi({ jsApiList: ['chooseImage'], // 須要檢測的JS接口列表,全部JS接口列表見附錄2, success: function(res) { console.log(res); // 以鍵值對的形式返回,可用的api值true,不可用爲false // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"} } }); }); wx.error(() => { }); }; export function chooseWXPay(data, This) {// 支付 wx.chooseWXPay({ timestamp: data.timeStamp, // 支付簽名時間戳,注意微信jssdk中的全部使用timestamp字段均爲小寫。但最新版的支付後臺生成簽名使用的timeStamp字段名需大寫其中的S字符 nonceStr: data.nonceStr, // 支付簽名隨機串,不長於 32 位 package: data.package, // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=\*\*\*) signType: data.signType, // 簽名方式,默認爲'SHA1',使用新版支付需傳入'MD5' paySign: data.paySign, // 支付簽名 success: function (res) { This.$router.push({ path: "/myReserve", query: { "reserve": "reservation" } }); } }); }; //拍照或從手機相冊中選圖接口 export function chooseImage(callback) { wx.chooseImage({ count: 6, // 默認9 sizeType: ['original', 'compressed'], // 能夠指定是原圖仍是壓縮圖,默認兩者都有 sourceType: ['album', 'camera'], // 能夠指定來源是相冊仍是相機,默認兩者都有 success: function (res) { callback(res); } }); }
三、在main.js中引用以下:
import Vue from "vue"; import * as wx "@/utils/wx"; Vue.use(wx);
三、頁面中引用分享方法
注意:若是這個頁面,咱們但願分享出去的內容,是按產品設計的內容,就須要在
方法中調用分享方法;若是咱們不關心這個頁面的分享的內容,咱們能夠不用調用配置好的分享方法,默認爲微信自帶的分享。
this.wx.setWxConfig(`${baseUrl}/tuijianDetail`,"我在小愛科技等你來~","驚喜多多!優惠多多!推薦好友關注有紅包~");
這樣使用微信右上角的分享功能,成功分享出去以後,就能夠看到想要的內容了。
同理,微信支付,須要調取微信支付api。因爲微信支付api,是在咱們點擊按鈕時觸發,全部就不須要寫在 wx.ready(() => {})裏面了。
export function chooseWXPay(data, This) {// 支付 wx.chooseWXPay({ timestamp: data.timeStamp, // 支付簽名時間戳,注意微信jssdk中的全部使用timestamp字段均爲小寫。但最新版的支付後臺生成簽名使用的timeStamp字段名需大寫其中的S字符 nonceStr: data.nonceStr, // 支付簽名隨機串,不長於 32 位 package: data.package, // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=\*\*\*) signType: data.signType, // 簽名方式,默認爲'SHA1',使用新版支付需傳入'MD5' paySign: data.paySign, // 支付簽名 success: function (res) { This.$router.push({ path: "/myReserve", query: { "reserve": "reservation" } }); } }); };
this.wx.chooseWXPay(res.result.list,This);
支付成功以後,經過路由跳轉到其餘頁面;
注意:微信api的成功驗證,必需要外網地址(可以訪問的服務器地址),若是使用本身本機的地址,放到手機上測試,是沒法成功的。
因爲最近項目的開發中,要使用到地圖進行相關的城市區域,區域中房源數據的顯示,所以選擇了使用百度地圖。
百度地圖JavaScript API是一套由JavaScript語言編寫的應用程序接口,可幫助您在網站中構建功能豐富、交互性強的地圖應用,支持PC端和移動端基於瀏覽器的地圖應用開發,且支持HTML5特性的地圖開發。
百度地圖JavaScript API支持HTTP和HTTPS,免費對外開放,可直接使用。接口使用無次數限制。
使用api以前,要註冊百度帳號,申請成爲百度開發者,獲取服務密鑰(ak),才能使用相關的服務功能。
開發步驟以下:
一、申請百度帳號和ak,點我申請
二、準備頁面
根據HTML標準,每一份HTML文檔都應該聲明正確的文檔類型,咱們建議您使用最新的符合HTML5規範的文檔聲明:
<!DOCTYPE html>
三、適應移動端頁面展現
下面咱們添加一個meta標籤,以便使您的頁面更好的在移動平臺上展現。
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
四、設置容器樣式
設置容器樣式大小,使地圖充滿整個瀏覽器窗口:
<style type="text/css"> html{height:100%} body{height:100%;margin:0px;padding:0px} #container{height:100%} </style>
五、在index.html中引用百度地圖API文件
<script type="text/javascript" src="http://api.map.baidu.com/api?v=3.0&ak=您的密鑰"></script>
六、建立地圖容器元素
地圖須要一個HTML元素做爲容器,這樣才能展示到頁面上。這裏咱們建立了一個div元素。
<div id="container"></div>
七、建立地圖實例
位於BMap命名空間下的Map類表示地圖,經過new操做符能夠建立一個地圖實例。其參數能夠是元素id也能夠是元素對象。
var map = new BMap.Map("container");
八、設置中心點座標
var point = new BMap.Point(116.404, 39.915);
九、地圖初始化,同時設置地圖展現級別
在建立地圖實例後,咱們須要對其進行初始化,BMap.Map.centerAndZoom()方法要求設置中心點座標和地圖級別。 地圖必須通過初始化才能夠執行其餘操做。
map.centerAndZoom(point, 15);
至此,咱們就快速建立了一張以天安門爲中心的地圖~
如圖:
咱們須要地圖初始化完成以後,自定義相關的方法,來添加覆蓋物;
根據官方文檔,自定義標註或地圖覆蓋物。具體的實現代碼,你們能夠根據官方api進行開發。
一、定義構造函數並繼承Overlay
首先您須要定義自定義覆蓋物的構造函數,經過構造函數參數能夠傳遞一些自由的變量。設置自定義覆蓋物對象的prototype屬性爲Overlay的實例,以便繼承覆蓋物基類。
// 定義自定義覆蓋物的構造函數 function SquareOverlay(center, length, color){ this._center = center; his._length = length; this._color = color; } // 繼承API的BMap.Overlay SquareOverlay.prototype = new BMap.Overlay();
二、初始化自定義覆蓋物
實現initialize方法,當調用map.addOverlay方法時,API會調用此方法。
當調用map.addOverlay方法添加自定義覆蓋物時,API會調用該對象的initialize方法用來初始化覆蓋物,在初始化過程當中須要建立覆蓋物所須要的DOM元素,並添加到地圖相應的容器中。這裏咱們選擇添加在容器markerPane上。
// 實現初始化方法 SquareOverlay.prototype.initialize = function(map){ // 保存map對象實例 his._map = map; // 建立div元素,做爲自定義覆蓋物的容器 var div = document.createElement("div"); div.style.position = "absolute"; // 能夠根據參數設置元素外觀 div.style.width = this._length + "px"; div.style.height = this._length + "px"; div.style.background = this._color; // 將div添加到覆蓋物容器中 map.getPanes().markerPane.appendChild(div); // 保存div實例 this._div = div; // 須要將div元素做爲方法的返回值,當調用該覆蓋物的show、 // hide方法,或者對覆蓋物進行移除時,API都將操做此元素。 return div; }
三、繪製覆蓋物
實現draw方法。
到目前爲止,咱們僅僅把覆蓋物添加到了地圖上,可是並無將它放置在正確的位置上。
您須要在draw方法中設置覆蓋物的位置,每當地圖狀態發生變化(好比:位置移動、級別變化)時,API都會調用覆蓋物的draw方法,用於從新計算覆蓋物的位置。
經過map.pointToOverlayPixel方法能夠將地理座標轉換到覆蓋物的所須要的像素座標。
css // 實現繪製方法 SquareOverlay.prototype.draw = function(){ // 根據地理座標轉換爲像素座標,並設置給容器 var position = this._map.pointToOverlayPixel(this._center); this._div.style.left = position.x - this._length / 2 + "px"; this._div.style.top = position.y - this._length / 2 + "px"; }
四、移除覆蓋物
當調用map.removeOverlay或者map.clearOverlays方法時,API會自動將initialize方法返回的DOM元素進行移除。
```css
map.removeOverlay();
五、添加覆蓋物 您如今已經完成了一個完整的自定義覆蓋物的編寫,能夠添加到地圖上了。
css
// 初始化地圖
var map = new BMap.Map("container");
var point = new BMap.Point(116.404, 39.915);
map.centerAndZoom(point, 15);
// 添加自定義覆蓋物
var mySquare = new SquareOverlay(map.getCenter(), 100, "red");
map.addOverlay(mySquare);
```
給地圖添加自定義控件,須要用到控件類:ZoomControl,使用方法以下:
css addControlLocation(){ var that = this; // 定義一個控件類,即function function ZoomControl(){ // 設置默認停靠位置和偏移量 this.defaultAnchor = BMAP_ANCHOR_BOTTOM_LEFT; this.defaultOffset = new BMap.Size(20, 50); } // 經過JavaScript的prototype屬性繼承於BMap.Control ZoomControl.prototype = new BMap.Control(); ZoomControl.prototype.initialize = function(map){ // 建立一個DOM元素 var img = document.createElement("img"); img.setAttribute('src',that.locationImg) // 設置樣式 img.style.cursor = "pointer"; // 綁定事件,獲取當前城市 img.onclick = function(e){... } // 添加DOM元素到地圖中 map.getContainer().appendChild(img); // 將DOM元素返回 return img; } // 建立控件實例 var myZoomCtrl = new ZoomControl(); // 添加到地圖當中 this.mp.addControl(myZoomCtrl); }
在地圖初始化完成後,調用addControlLocation()方法便可;
如圖:
須要用到new BMap.Marker();設置圖標大小用 myIcon.setImageSize();
css addCurrentMarker(){ // 添加自定義 當前位置定位標註 var myIcon = new BMap.Icon(this.redLocation,{ offset: new BMap.Size(10, 25), // 指定定位位置 imageOffset: new BMap.Size(0, 0 - 10 * 25) // 設置圖片偏移 }); // myIcon.setStyle({width: '.666rem', height: '.666rem'}); myIcon.setImageSize(new BMap.Size(60,60)); // 設置 圖標大小 let point = new BMap.Point(this.currentPoint.lng,this.currentPoint.lat); // 標註的中心點,應該是始終是用戶當前位置 let marker = new BMap.Marker(point,{icon:myIcon}); // 建立Marker標註 this.mp.addOverlay(marker); // 添加當前定位點 },
this.mp.addEventListener("touchstart", () => {});
this.mp.addEventListener("zoomend", () => {});
this.mp.addEventListener("dragstart",()=>{}); this.mp.addEventListener("dragend",()=>{});
export function getLocationData(fn) { let geolocation = new BMap.Geolocation(); geolocation.getCurrentPosition(function (r) { if (this.getStatus() == BMAP_STATUS_SUCCESS) { fn(r.point); } }); }
let gc = new BMap.Geocoder();//Geocoder地址編碼 gc.getLocation(item, function (rs) { //getLocation函數用來解析地址信息,分別返回省市區街等 r.point裏有經緯度 let addComp = rs.addressComponents; let province = addComp.province;//獲取省份 let city = addComp.city;//獲取城市 });
項目實踐:基於vue2.0 +vuex+ element-ui後臺管理系統
歡迎加入討論組,一塊兒來學習用vue,vuex,element,express,mongodb來構建後臺管理系統;
一塊兒來用項目實戰加深本身對知識的理解。