Skip to main content

Navbar Weather Widget Strategy and Implementation

This document records the product strategy, implementation approach, and troubleshooting guide for the navbar weather widget.

The current widget is not a server-side weather component, nor does it display weather for the server's location. It runs in the browser, uses the AMap JSAPI to identify the visitor's city, and queries weather for that city. Implementation code lives in src/components/NavbarWeather/index.js; AMap loading and security configuration reuse src/utils/amap.js.

Target Strategy

The weather widget uses an on-demand loading strategy and no longer auto-requests the weather API on page load:

  1. After page load, only check the sessionStorage cache. If a valid cache exists, render the weather immediately with no network request.
  2. If no cache exists, display placeholder text (weather?) and call no AMap APIs.
  3. On the user's first click, request browser geolocation permission. After authorization, query weather using the precise district or city.
  4. If browser geolocation fails, the user denies permission, or reverse geocoding fails, fall back to AMap IP geolocation.
  5. If IP geolocation also fails, fall back to the default city: Chengdu.

If cached data already exists on click, browser-geolocated weather only expands the detail panel without re-requesting. IP or default city weather will attempt browser geolocation on the next click.

The reasons behind this approach:

  • AMap API quota is limited; avoid consuming quota on every page visit.
  • Cache hits render instantly -- fast and quota-free.
  • Weather requests only fire after the user actively clicks, avoiding API consumption on page load.
  • Browser geolocation is closest to the user's real position and is the preferred path after a click.
  • IP geolocation requires no user permission and serves as a fallback when browser geolocation fails.
  • The default city keeps the widget visible across public networks, proxies, overseas connections, and data center exits.

Default city configuration:

City: Chengdu
adcode: 510100

Initialization Flow

On mount, the widget no longer auto-requests the weather API; it only checks the cache:

Check sessionStorage cache (key: navbar-weather-v3, TTL: 30 minutes)
-> Cache valid: render weather button immediately
-> Cache invalid or missing: render placeholder button (shows "weather?")

When rendering the placeholder button, the widget does not load the AMap JSAPI and makes no network requests.

The widget depends on useAmapConfig() to read customFields.amap. If key is missing, or both serviceHost and securityJsCode are missing, the widget stays hidden.

First Click Flow

When the user clicks the weather widget for the first time (no cached data):

Request navigator.geolocation.getCurrentPosition()
-> On success, load AMap JSAPI plugins: CitySearch, Geocoder, Weather
-> Call AMap.convertFrom(..., 'gps') to convert to AMap-compatible coordinates
-> Call Geocoder.getAddress() to look up district, city, and adcode
-> Prefer district/adcode to query weather and display the district name
-> If browser geolocation, coordinate conversion, reverse geocoding, or weather query fails, call CitySearch.getLocalCity()
-> If IP geolocation also fails, query weather for Chengdu (510100)
-> On success, render the navbar button, expand the detail panel, and write to sessionStorage cache

When browser geolocation succeeds, the weather data is tagged:

source: browser

When IP geolocation succeeds:

source: ip

When the default city fallback succeeds:

source: default

This source field is the key to the subsequent click strategy. The widget uses it to decide whether to request browser geolocation on the next click.

Subsequent Click Flow (When Weather Data Already Exists)

When the user clicks the widget with existing weather data, the widget first toggles the detail panel.

Then it decides whether to request browser geolocation based on the current source:

  • source: ip: the user's city was identified by IP; the click will attempt browser geolocation.
  • source: browser: already updated via browser geolocation; only expand the detail, do not re-request permission.
  • source: default: currently showing Chengdu fallback weather; the click requests browser geolocation.

Browser geolocation flow:

navigator.geolocation.getCurrentPosition()
-> Get WGS84/GPS latitude and longitude
-> Call AMap.convertFrom(..., 'gps') to convert to AMap-compatible coordinates
-> Load AMap.Geocoder
-> Call geocoder.getAddress() to look up city and adcode
-> Use adcode to query live weather and forecast
-> Update widget and refresh sessionStorage cache

If the user denies permission, the browser does not support geolocation, the request times out, coordinate conversion fails, reverse geocoding fails, or the weather query fails, the widget does not show an error and does not hide. It continues to display IP or Chengdu fallback weather.

Why IP Geolocation Alone Is Not Enough

IP geolocation only identifies the public network exit IP, not the user's actual GPS position.

The following network environments frequently cause IP geolocation to fail or return inaccurate results:

  • Campus networks, corporate networks, hotel networks with shared exits
  • Mobile carrier NAT exits
  • VPNs, proxies, accelerators
  • Overseas networks or cross-border exits
  • Cloud servers, data centers, CDNs, or remote browser environments
  • Address ranges not yet in AMap's IP database

During live debugging, the AMap IP endpoint returned:

{
"status": "1",
"info": "OK",
"infocode": "10000",
"province": [],
"city": [],
"adcode": [],
"rectangle": []
}

This type of response means the request succeeded but returned no usable city data. The old logic would hide the widget; the new logic falls back to Chengdu weather.

Caching Strategy

The widget caches weather data in sessionStorage:

key: navbar-weather-v3
ttl: 30 minutes

The cache goal is to reduce redundant AMap API calls within the same browsing session.

Cached content includes:

  • City name
  • adcode
  • Province
  • Live weather
  • Temperature
  • Humidity
  • Wind direction and force
  • Forecast list
  • Data source source
  • Report time

Expired or unparseable cache is ignored without affecting re-requests.

AMap JSAPI Dependencies

The widget loads AMap plugins in two groups on demand:

  • Without browser geolocation: loads AMap.CitySearch and AMap.Weather for IP geolocation and weather queries.
  • With browser geolocation: loads AMap.CitySearch, AMap.Geocoder, and AMap.Weather for coordinate lookup, IP fallback, and weather queries.

AMap authentication config comes from Docusaurus customFields.amap:

customFields: {
amap: {
key,
serviceHost,
securityJsCode,
},
}

The widget only attempts to load the AMap JSAPI when key exists and either serviceHost or securityJsCode is present.

Widget Hide Conditions

The widget currently hides under these conditions:

  • The mobile navbar item render path passes mobile.
  • AMap JSAPI key or security config is missing.
  • AMap JSAPI fails to load and no usable cache exists.
  • Chengdu fallback weather also fails and no usable cache exists.
  • CSS media query matches max-width: 996px.

Beyond these, IP geolocation failure alone no longer hides the widget.

Privacy and Interaction Principles

The initial page load does not fire any weather API requests and does not request location permission. Weather data is only fetched after the user actively clicks the widget.

Precise browser geolocation is only requested after the user actively clicks the weather widget. If the current display is IP or default city weather, subsequent clicks will attempt browser geolocation.

The implementation does not proactively save precise latitude/longitude and does not write coordinates to the cache. The cache only stores the city, adcode, and weather data needed for the query.

This maintains two boundaries:

  • Zero API consumption and zero permission requests on initial page load -- no user disruption.
  • Authorized geolocation is used only for this weather city update; precise location is not stored long-term in site storage.

Troubleshooting Checklist

If the weather widget is not appearing in production, check in this order:

  1. Confirm the viewport width is greater than 996px.
  2. Confirm the page has loaded main.*.js and it contains custom-weather related code.
  3. After clicking the widget, confirm window._AMapSecurityConfig exists.
  4. After clicking the widget, confirm window.AMap is loaded.
  5. Check that AMap JSAPI, plugins, and weather requests return 200.
  6. Check sessionStorage.navbar-weather-v3 for valid data.
  7. If IP geolocation returns an empty city, confirm the widget falls back to source: default Chengdu weather.
  8. If clicking does not switch the city, check whether the browser denied geolocation permission or the old source: browser cache is still active.

Local verification with a production build:

npm run build
npm run serve -- --host 127.0.0.1 --port 3002

At desktop width, after granting browser geolocation, clicking the widget should switch to the corresponding district or city weather. If geolocation fails, you should at least see IP or Chengdu weather.

  • src/components/NavbarWeather/index.js
  • src/components/NavbarWeather/styles.module.css
  • src/utils/amap.js
  • docusaurus.config.js