微信小程序中自定義導航和地圖定位

在健康碼中,主要的難點技術就是在小程序中定位、自定頂部導航。

自定義導航

在微信小程序中,默認的頂部導航不能設置圖片背景或者是透明背景,只能自定義導航。

在每一個頁面中引入,就是得到自己定義【個性化的】導航。

第一步:

現在app.json文件中配置

"window": {
    "navigationStyle": "custom"
  },

"navigationStyle": "custom"設置爲使用自定義導航。

第三步:

開始定義導航

navbar.wxml:

<view class='nav-wrap'>
  <!-- 導航欄背景圖片 -->
  <!-- <image class="backgroundimg" src="{{bg}}" bindload="imgLoaded"/> -->
  <!-- // 導航欄 中間的標題 -->
  <view class='nav-title'  style='line-height: {{height*2 + 44}}px; color:#fff'>
    {{navbarData.title}}
  </view>
</view>

navbar.js

const app = getApp()
Component({
  properties: {
    navbarData: {
      //navbarData   由父頁面傳遞的數據,變量名字自命名
      type: Object,
      value: {},
      observer: function(newVal, oldVal) {}
    }
  },
  data: {
    height: '',
    //默認值  默認顯示左上角
    navbarData: {
      showCapsule: 1
    },
    imageWidth: wx.getSystemInfoSync().windowWidth, // 背景圖片的高度
    imageHeight: '', // 背景圖片的長度,通過計算獲取
    
  },
  attached: function() {
    // 獲取是否是通過分享進入的小程序
    this.setData({
      share: app.globalData.share
    })
    // 定義導航欄的高度   方便對齊
    this.setData({
      height: app.globalData.height
    })
  },
  methods: {
    // 返回上一頁面
    _navback() {
      wx.navigateBack()
    },
    // 計算圖片高度
    imgLoaded(e) {
      console.log(e.detail.height)
      this.setData({
        imageHeight: e.detail.height *  
          (wx.getSystemInfoSync().windowWidth / e.detail.width)
      })
    },
    tapName: function () {
      console.log(0)
    }
    //返回到首頁
    // _backhome() {
    //   wx.switchTab({
    //     url: '/pages/index/index'
    //   })
    // }
  },
})

在app.js中獲取設備頂部窗口的高度,會根據這個值來設置自定義導航欄的高度

//app.js
App({
  onLaunch: function(e) {
    console.log(e)
    // 展示本地存儲能力
    var logs = wx.getStorageSync('logs') || []
    logs.unshift(Date.now())
    wx.setStorageSync('logs', logs)

    // 登錄
    wx.login({
      success: res => {
        // 發送 res.code 到後臺換取 openId, sessionKey, unionId
      }
    })
    // 獲取用戶信息
    wx.getSetting({
      success: res => {
        if (res.authSetting['scope.userInfo']) {
          // 已經授權,可以直接調用 getUserInfo 獲取頭像暱稱,不會彈框
          wx.getUserInfo({
            success: res => {
              // 可以將 res 發送給後臺解碼出 unionId
              this.globalData.userInfo = res.userInfo

              // 由於 getUserInfo 是網絡請求,可能會在 Page.onLoad 之後才返回
              // 所以此處加入 callback 以防止這種情況
              if (this.userInfoReadyCallback) {
                this.userInfoReadyCallback(res)
              }
            }
          })
        }
      }
    })
    wx.getSystemInfo({
      success: res => {
        console.log(res)
        this.globalData.height = res.statusBarHeight
      }
    })
  },
  globalData: {
    userInfo: null,
    height: 0 // 頂部高度
  }
})

navbar.wxss

/* navbar.wxss */

/* 頂部要固定定位   標題要居中   自定義按鈕和標題要和右邊微信原生的膠囊上下對齊 */

.nav-wrap {
  position: fixed;
  width: 100%;
  top: 0;
  background-image: linear-gradient(#2f52bc, #9198e5, #d0d9f4);
  color: #000;
  z-index: 9999999;
  overflow: hidden;
  height: 400rpx;
}

/* 背景圖 */
.backgroundimg {
  position: absolute;
  z-index: -1;
  width: 100%;
  height: 100%;
}

/* 標題要居中 */

.nav-title {
  position: absolute;
  text-align: center;
  max-width: 400rpx;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
  font-size: 36rpx;
  color: #2c2b2b;
  font-weight: 450;
}

.nav-capsule {
  display: flex;
  align-items: center;
  margin-left: 30rpx;
  width: 140rpx;
  justify-content: space-between;
  height: 100%;
}

.back-pre {
  width: 32rpx;
  height: 36rpx;
  margin-top: 4rpx;
  padding: 10rpx;
}

.nav-capsule {
  width: 36rpx;
  height: 40rpx;
  margin-top: 3rpx;
}

navbar.json:

{
  "component": true,
  "usingComponents": {}
}

在index中引入導航

index.json:

{
  "usingComponents": {
    "nav-bar": "../component/navbar/index"
  },
  "navigationBarTextStyle": "white"
  
}

index.js:

Page({
    data:[
        nvabarData: {
          showCapsule: 1, //是否顯示左上角圖標   1表示顯示    0表示不顯示
          title: '健康碼', //導航欄 中間的標題
          white: true, // 是就顯示白的,不是就顯示黑的。
        }
    ]
})

index.wxml:

<nav-bar navbar-data='{{nvabarData}}'></nav-bar>

以上是首頁引用的自定義導航,重新定義其他頁面的導航:

wxml:

<view class='nav-wrap'>
  <!-- 導航欄背景圖片 -->
  <!-- <image class="backgroundimg" src="{{bg}}" bindload="imgLoaded"/> -->
  <!-- // 導航欄 中間的標題 -->
  <view class='nav-title' wx:if='{{!navbarData.white}}' style='line-height: {{height*2 + 44}}px;'>
    {{navbarData.title}}
  </view>
  <view class='nav-title' wx:else='{{!navbarData.white}}' style='line-height: {{height*2 + 44}}px; color:#fff'>
    {{navbarData.title}}
  </view>
  <view style='display: flex; justify-content: space-around;flex-direction: column'>
    <view class='nav-capsule' style='height: {{height*2 + 44}}px;'>
      <view bindtap='_navback'>
        <image src='{{backIcon}}' mode='aspectFit' class='back-pre'></image>
      </view>
    </view>
  </view>
</view>

wxss:

/* navbar.wxss */

/* 頂部要固定定位   標題要居中   自定義按鈕和標題要和右邊微信原生的膠囊上下對齊 */

.nav-wrap {
  position: fixed;
  width: 100%;
  top: 0;
  background-image: linear-gradient(#2f52bc, #9198e5, #d0d9f4);
  color: #000;
  z-index: 9999999;
  overflow: hidden;
  
}

/* 背景圖 */

.backgroundimg {
  position: absolute;
  z-index: -1;
  width: 100%;
  height: 100%;
}

/* 標題要居中 */

.nav-title {
  position: absolute;
  text-align: center;
  max-width: 400rpx;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
  font-size: 36rpx;
  color: #2c2b2b;
  font-weight: 450;
}

.nav-capsule {
  display: flex;
  align-items: center;
  margin-left: 30rpx;
  width: 140rpx;
  justify-content: space-between;
  height: 100%;
}

.back-pre {
  width: 32rpx;
  height: 36rpx;
  margin-top: 4rpx;
  padding: 10rpx;
}

.nav-capsule {
  width: 36rpx;
  height: 40rpx;
  margin-top: 3rpx;
}

json:

{
  "component": true,
  "usingComponents": {}
}

js:

const app = getApp()
Component({
  properties: {
    navbarData: {
      //navbarData   由父頁面傳遞的數據,變量名字自命名
      type: Object,
      value: {},
      observer: function(newVal, oldVal) {}
    }
  },
  data: {
    height: '',
    //默認值  默認顯示左上角
    navbarData: {
      showCapsule: 1
    },
    imageWidth: wx.getSystemInfoSync().windowWidth, // 背景圖片的高度
    imageHeight: '', // 背景圖片的長度,通過計算獲取
    backIcon: "../../img/fanhui.png",
  },
  attached: function() {
    // 獲取是否是通過分享進入的小程序
    this.setData({
      share: app.globalData.share
    })
    // 定義導航欄的高度   方便對齊
    this.setData({
      height: app.globalData.height
    })
  },
  methods: {
    // 返回上一頁面
    _navback() {
      wx.navigateBack()
    },
    // 計算圖片高度
    imgLoaded(e) {
      console.log(e.detail.height)
      this.setData({
        imageHeight: e.detail.height *  
          (wx.getSystemInfoSync().windowWidth / e.detail.width)
      })
    },
    tapName: function() {
      console.log(0)
    }
    //返回到首頁
    // _backhome() {
    //   wx.switchTab({
    //     url: '/pages/index/index'
    //   })
    // }
  },
})

其實可以不用定義兩個導航,只要navbar.js判斷是否是通過分享進入小程序或者是當前頁面是否是首頁,來決定隱藏/顯示導航左上角的返回按鈕。

地圖定位

在監聽小程序初次渲染完成時,通過apiwx.getLocation獲取小程序當前的經緯度,再通過經緯度在地圖給小程序進行定位。但是這個API需要用戶授權後才能獲取到,只需要在首次打開小程序時 進行授權即可。

在app.json設置:

"permission": {
    "scope.userLocation": {
      "desc": "你的位置信息將用於小程序位置接口的效果展示"
    }
  }

在這裏插入圖片描述
授權過後,在首頁的index.js中的onReady監聽頁面渲染函數中獲取小程序的經緯度:

  onReady: function() {
    const that = this;
    const markers = that.data.markers;
    wx.getLocation({
      type: 'wgs84',
      success(res) {
        markers.latitude = res.latitude;
        markers.longitude = res.longitude;
        that.setData({
          latitude: res.latitude,
          longitude: res.longitude,
          markers: markers
        })
        const latitude = res.latitude
        const longitude = res.longitude
      }
    })
  },

index.js完整代碼如下:

//index.js
//獲取應用實例
const app = getApp()
Page({
  data: {
    markers: [{  //地圖標註的信息
      iconPath: "../resources/location.png",
      id: 0,
      latitude: 26.64702,
      longitude: 106.63024,
      width: 50,
      height: 50
    }],
    latitude: 26.64702,
    longitude: 106.63024,
    nvabarData: {
      showCapsule: 1, //是否顯示左上角圖標   1表示顯示    0表示不顯示
      title: '健康碼', //導航欄 中間的標題
      white: true, // 是就顯示白的,不是就顯示黑的。
    },
    // 導航頭的高度
    height: app.globalData.height * 2 + 20,

    userImg: "../img/user1.png",
    cradImg: "../img/user2.png",
    clickCradimg: "../img/jilu.png",
    rightimg: "../img/rightimg.png"
  },
  onLoad: function() {},
  onReady: function() {
    const that = this;
    const markers = that.data.markers;
    wx.getLocation({
      type: 'wgs84',
      success(res) {
        console.log(res)
        markers.latitude = res.latitude;
        markers.longitude = res.longitude;
        that.setData({
          latitude: res.latitude,
          longitude: res.longitude,
          markers: markers
        })
        const latitude = res.latitude
        const longitude = res.longitude
      }
    })
  },
  login: function() {
    wx.navigateTo({
      url: '/pages/userinfo/index',
    })
  },
  card: function() {
    wx.navigateTo({
      url: '/pages/card/index',
    })
  },
  punchCard: function() {
    wx.navigateTo({
      url: '/pages/punchcard/index',
    })
  }
})

index.wxml

<nav-bar navbar-data='{{nvabarData}}'></nav-bar>
<map id="map" longitude="{{longitude}}" latitude="{{latitude}}" scale="14" bindcontroltap="controltap" markers="{{markers}}"  show-location>
</map>

<view class="info">
  <view class="login" bindtap="login">
    <image src="{{userImg}}"></image>
    <view>信息登錄</view>
  </view>
  <view class="crad" bindtap="card">
    <image src="{{cradImg}}"></image>
    <view>健康卡</view>
  </view>
</view>
<view class="clickCrad" bindtap="punchCard">
  <view class="left">
    <image class="cradImg" src="{{clickCradimg}}"></image>
    <view>每日健康打卡</view>
  </view>
  <image src="{{rightimg}}" class="rightImg"></image>
</view>

index.wxss:

#map {
  width: 100%;
  height: 100%;
}

.info {
  position: fixed;
  top: 250rpx;
  padding: 30rpx 100rpx;
  background: #fff;
  border-radius: 10px;
  display: flex;
  justify-content: space-between;
  font-weight: bold;
  z-index: 99999999999;
  left: 0;
  right: 0;
  margin: 0 40rpx;
}

.info image {
  width: 100rpx;
  height: 100rpx;
}

.login {
  text-align: center;
}

.crad {
  text-align: center;
}

.clickCrad {
  background: #fff;
  margin: 10rpx 40rpx 20rpx 40rpx;
  padding: 20rpx 100rpx;
  border-radius: 10px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: fixed;
  top: 500rpx;
  right: 0;
  left: 0;
  z-index: 999999999999;
}

.left {
  display: flex;
  align-items: center;
}

.cradImg {
  width: 50rpx;
  height: 50rpx;
  margin-right: 10px;
}

.rightImg {
  width: 35rpx;
  height: 35rpx;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章