1. ホーム
  2. Web制作
  3. html5

Html5ポジショニングの究極のソリューション

2022-01-14 22:43:17

背景

新会社への2つ目のプロジェクトは、WeChat内を中心に、他のブラウザも考慮したH5モールを小さなパートナーたちと作ることです。中でもホームページは、現在のユーザーの緯度・経度から最も近い店舗を探し出し、表示する必要があります。フロントエンドが行うべき作業は、ユーザーの緯度と経度を取得し、バックグラウンド・インターフェースに問い合わせ、ページをレンダリングすることです。

目標と分析

私たちの目標は、カプセル化された後に返される位置情報を、たった一つのメソッドを呼び出すことで取得することです。

必要なことは、異なるエンド(WeChat H5と他のブラウザ環境)に対して異なるクラスをカプセル化し、異なる環境に対応するクラスを呼び出し、UAによって区別された一つのメソッドを通じて位置を取得することである。

WeChatの内部では、繰り返し練習した後、ネイティブのHTML5の測位を介して、またはサードパーティ(百度や騰訊マップなど)のjsapiを介して位置を取得するかどうか、測位時間が長いだけでなく、さらにしばしば失敗し、真剣にユーザー体験、特に情報の流れのほとんどは、位置のために使用するショッピングモールのホームページに依存して、それは完全に容認できるものではありません。だから、WeChatの中で我々は唯一のオプションとしてWeChatのsdkを持っている。

ブラウザ側では、サードパーティーのmap jsapiやlocation componentで位置情報を安定的かつ高速に取得できるため、WeChatとの整合性を図るため、Tencent map jsapiを選択しました。

解決方法

口は災いの元、コードを見せよ。

1. ブラウザで、Tencent Maps jsapi経由で位置情報を取得する。

1.1 プロジェクトのhtmlテンプレートファイルにTencent Maps jsapiを導入する。

<! -- index.html -->
<script charset="utf-8" src="https://map.qq.com/api/js?v=2.exp&key=Tencent map key&referer=Application name"></ script>


説明

Tencent Map jsapiを使用するには、Tencent Mapオープンプラットフォームで自分のアカウントを申請し、自分のアプリケーションを作成し、上記の値をTencent Mapキーと作成したアプリケーションの名前に置き換える必要があります。

1.2 Get Locationインターフェイスを呼び出して位置情報を取得する

再利用を容易にするため、Tencent Maps jsapi クラスを別途パッケージ化し、tMap.js と名付けました。

// tMap.js
const qq = window.qq
var geolocation = null
if (qq && qq.maps) {
  // Initialize the location component
  geolocation = new qq.maps.Geolocation(
    'QVLBZ-YUULR-OUMW7-WKXFD-4SUWS-UDBIA',
    'mymap'
  )
}

class TMap {
  // Get the position counter to accumulate the number of position failures after 3 times and throw a position failure error
  getPositionCount = 0

  // Externally exposed interface to get location
  getLocation () {
    return new Promise((resolve, reject) => {
      // Location success callback
      this.getTMapLocation(resolve, reject)
    })
  }

  // Call Tencent Maps to get the location
  getTMapLocation (success, fail) {
    const _self = this

    // Callback for successful location
    const showPosition = position => {
      uni.setStorage({
        key: 'positionData',
        data: position
      })
      success(position)
    }

    // Positioning failure callback
    const showErr = (err) => 
      // if get position fails more than 3 times throw an error otherwise continue to get position information
      if (this.getPositionCount > 3) {
        fail('Failed to get position more than 3 times')
      } else {
        // Positioning failure recursion
        _self.getPositionCount = _self.getPositionCount + 1
        _self.getTMapLocation(success, fail)
      }
    }

    // Call the Tencent web location component to get the location information
    if (geolocation) {
      geolocation.getIpLocation(showPosition, showErr, {
        timeout: 6000, // location timeout in ms
        failTipFlag: true
      })
    }
  }
}

export default new TMap()



2. WeChatのウェブビューで、WeChat sdkを通じて位置情報を取得する。

2.1 WeChat js-sdk関連の準備
2.1.1 jsファイルの導入

/**
 * microsoft sdk asynchronous loading
 * @param {*} src
 * @param {*} callback api interface
 *export const handlerLoadScript = callback => {
  const src = `https://res.wx.qq.com/open/js/jweixin-1.4.0.js`
  if (! (typeof callback === 'function')) {
    callback = function() {}
  }
  var check = document.querySelectorAll(`script[src="${src}"]`)
  if (check.length > 0) {
    check[0].addEventListener('load', function() {
      callback()
    })
    callback()
    return
  }
  var script = document.createElement('script')
  var head = document.getElementsByTagName('head')[0]
  script.type = 'text/javascript'
  script.charset = 'UTF-8'
  script.src = src
  if (script.addEventListener) {
    script.addEventListener(
      'load',
      function() {
        callback()
      },
      false
    )
  } else if (script.attachEvent) {
    script.attachEvent('onreadystatechange', function() {
      var target = window.event.srcElement
      if (target.readyState === 'loaded') {
        callback()
      }
    })
  }
  head.appendChild(script)
}


2.1.2 権限検証の設定を注入する
JS-SDK を使用する必要があるすべてのページは、最初に設定情報を注入する必要があり、そうでない場合は呼び出されません。通常、設定情報はバックエンドインターフェースを通じて取得されます。

/**
 * Inject permission validation configuration
 * @param {object} microsoft js-sdk permission validation configuration
 *export const wxconfigInfo = config => {
  wx.config({
    debug: false, // enable debug mode, the return value of all api calls will be alerted out on the client side, if you want to see the incoming parameters, you can open it on the pc side, the parameter information will be typed out via log, it will only be printed when on the pc side.
    appId: config.appId,
    timestamp: parseInt(config.timestamp),
    nonceStr: config.nonceStr,
    signature: config.signature,
    jsApiList: [ // list of jsapi to use
      ... ,
      'getLocation' // Get the geographic location
    }
  })
}



2.2 位置情報を取得するためのapiの呼び出し

 /**
 * WeChat get location
 *export const handleGetLocation = (config) => {
  return new Promise((resolve, reject)=>{
    wxconfigInfo(config)
    wx.ready(function () {
      wx.getLocation({
        type: 'wgs84', // default is the gps coordinates of wgs84, if you want to return the Mars coordinates directly to openLocation, you can pass 'gcj02'
        success: function (res) {
          console.warn('WeChat sdk location success', res)
          resolve({
            lat: res.latitude, // latitude
            lng: res.longitude, // longitude
            speed: res.speed, // speed in meters per second
            accuracy: res.accuracy // position accuracy
          })
        },
        fail: function (err) {
          console.error('WeChat sdk location failed', err)
          reject(err)
        }
      })
    })
    wx.error(function(err) {
      // config information verification failure will execute the error function, such as signature expiration lead to verification failure, the specific error information can open the debug mode of the config to view, but also in the returned res parameter to view, for SPA can update the signature here.
      console.log('wxjsapi-error=', err)
      reject(`wxjsapi-error: ${err}`)
    })
  })


2.3 実行環境に応じて異なるポジショニングメソッドを呼び出す

// public.js

/**
 * UA enumeration
 *const UA = {
  /**
   * WeChat h5
   *  WECHAT: 'WECHAT',
  /**
   * Alipay h5
   *  ALIPAY: 'ALIPAY',
  /**
   * Other
   *  OTHERS: 'OTHERS'
}


/**
 * Determine the client runtime environment Here only determine the WeChat and browser h5
 *export const getUserAgent = () => {
  var userAgent = navigator.userAgent.toLowerCase()

  if (userAgent.match(/Alipay/i) == 'alipay') {
    return UA.ALIPAY
  } else if (userAgent.match(/MicroMessenger/i) == 'micromessenger') {
    return UA.WECHAT
  } else {
    return UA.OTHERS
  }
}


// js-sdk.js
/**
 * Calling up the microsoft api
 * @param {*} _href current page url
 * @param {*} options sharing information
 * @param {*} apiType Call api type
 *export const handleWXSDKCall = (_href, apiType, options) => {
  return new Promise((resolve, reject)=>{
    // Get configuration information through the backend interface
    WeChatServivce.sign(_href)
      .then(res => {
        if (res) {
          if ( apiType === 'location' ) {
            handleGetLocation(res).then((res)=> {
              resolve(res)
            }).catch(err=>{
              reject(err)
            })
          }
        }
      })
      .catch(err => {
        reject(`err-sign: ${err}`)
        uni.showToast({
          title: err.data.code + err.data.msg,
          mask: true,
          icon: 'none'
        })
      })
  })
}



// getLocation.js
import { getUserAgent, handlerLoadScript } from '@/module/utils'
import { handleWXSDKCall } from '@/module/utils/wechat/wxJsApiSdk'
import UA from '@/module/enums/userAgent'
import TMap from '@/module/utils/tMap'

/**
 * Externally exposed method to get the location
 * @return Promise resolve a positionData object lat-latitude lng-longitude
 *const getLocation = () => {
  return new Promise((resolve, reject) => {
    console.log('Enter global get user location method')
    const storageData = uni.getStorageSync('positionData')
    const userAgent = getUserAgent()
    if (storageData) {
      resolve(storageData)
    } else {
      // Determine based on environment If using WeChat sdk within WeChat Other using Tencent map location component
      if (userAgent === UA.WECHAT) {
        handlerLoadScript(() => {
          handleWXSDKCall(window.location.href, 'location').then((res) => {
            uni.setStorageSync('positionData', res)
            resolve(res)
          }).catch(err => {
            reject(err)
          })
        })
      } else {
        TMap.getLocation().then(res => {
          uni.setStorageSync('positionData', res)
          resolve(res)
        }).catch((err) => {
          reject(err)
        })
      }
    }
  })
}

export default getLocation



3. ページ呼び出し

3.1 Vueのプロトタイプにメソッドをバインドする

import getLocation from '@/module/utils/getLocation'
Vue.prototype.$getLocation = getLocation


3.2 ページコンポーネントでの呼び出し

onShow() {
  // Get the location information and request the backend interface
  this.$getLocation()
    .then(res => {
      console.warn('Home page get location success', res)
      this.latitude = res.lat
      this.longitude = res.lng
      // Here the backend interface is requested based on the latitude and longitude obtained...
    })
    .catch(err => {
      console.error('Home page failed to get location', err)
      // Error handling
    })
}

概要

遭遇した落とし穴と注意点。

WeChat sdkを使用して位置情報を取得するためには、以下のステップを完了する必要があります。

  • WeChat sdkを非同期でロードする。
  • インターフェースを通して設定情報を取得し、WeChat sdkを設定します。
  • wx.readyコールバック内のメソッドを呼び出す

上記の3つのステップを厳密な順序で完了しなければ、WeChat sdk の機能を呼び出すことはできません。

つまり、この記事を読めば、H5ポジショニングの適用シーンの99%以上を解決することができるのです。

以上、本記事の内容をご紹介しましたが、ご参考になれば幸いです。