在授予的地理定位权限上附加事件侦听器
Attach event listener on geolocation permission granted
我的设置:
我有一些非常简单的代码:
const onSuccess = () => {
console.log('success');
}
const onError = () => {
console.log('error');
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
我的实际代码包含更多逻辑。但为简单起见,我只发布了所需的代码。
- 我第一次访问该页面时被要求获得许可。
- 让我们假设,我授予使用我的地理位置的权限。
success
打印到控制台。
目前一切顺利...
实际问题:
- 每次刷新页面时,我都会
success
登录到控制台。
- 其实我想要不一样的东西。当用户授予使用地理定位的访问权限时,我只想调用我的函数一次。
现在,如果用户阻止地理定位并且再次允许浏览器使用地理定位,那么在那个时候,success
应该被记录。但是在每次刷新时,它不应该记录 success
.
所以,我相信,允许按钮上应该有某种事件侦听器,但我没有看到任何地方提到它。
我的研究:
我不确定我的方向是否正确,但是...
在 MDN 文档 here 上,我可以看到有一个叫做 PermissionStatus.onchange
.
的东西
但它是实验性的,不支持 Internet Explorer、Safari 和 Safari iOS。
如果你们中有人使用过任何替代方案,那么我很乐意检查你的想法。
实际用例
我正在开发天气应用程序。要求是:
当用户登陆网站时,应该要求他获得地理定位许可(如果尚未授予)
一旦用户授予权限,他应该被带到可以查看他所在城市的天气详细信息的页面。
目前的问题是,每次我刷新页面时,它都会检测到用户的位置并将用户带到他的城市详细信息页面。这是不好的。这应该只发生一次,只有当用户授予对地理定位的访问权限时。
我的实际技术栈
- 反应
- 打字稿
更新:
我收到了一些将用户权限状态存储到本地存储的建议。
但是,如果我将权限存储在本地存储中,则会遇到一些问题。
我举个例子详细解释一下
部分直到一切正常:
- 如果用户授予读取其位置的权限。
- 然后我把他带到城市详情页面。
- 然后我保存在用户已授予权限的本地存储中。
- 现在如果用户刷新页面,那么一切似乎都正常。
当我遇到问题时:
- 现在用户进入 chrome 设置并删除我网站的位置权限。
- 然后用户刷新我的网站,他会看到一个弹出窗口,要求他提供位置权限。
- 如果他随后允许该权限,那么我将无法知道用户再次允许该权限,因为在我的本地存储中,我已经存储了位置授权。所以,我无法将他带到城市详细信息页面。
您可以将权限状态保存到本地存储,并在每次页面刷新时检查权限是否已更改:
const onSuccess = () => {
console.log('success');
if (localStorage.getItem("permission_status") !== "ok") {
// fire permission onchange event
// update local storage
}
}
const onError = () => {
console.log('error');
if (localStorage.getItem("permission_status") === "ok") {
// fire permission onchange event
// update local storage
}
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
我的建议不是保存用户的权限状态,而是在成功回调中保存用户的 GeolocationPosition
对象。
所以你可以比较对象而不是比较权限状态。
由于 macOS 浏览器不支持,您无法使用 navigator.permissions
,唯一的解决方案是保存坐标数据本身以供比较。
因此您的代码将如下所示:
const onSuccess = (pos) => {
if (localStorage.getItem("latitude") !== pos.coords.latitude ||
localStorage.getItem("longitude") !== pos.coords.longitude)
{
// fire permission onchange event
// update local storage
console.log('success');
}
}
const onError = () => {
console.log('error');
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
编辑
刚看到你对@Zeke Hernandez 的评论。这是独立于权限的解决方案,所以我认为它应该适合你。
我不知道你是如何渲染用户的城市详情页面,但我相信你会使用用户的位置数据来渲染页面,我们可以在成功回调中使用我们保存到本地存储的数据。
我没有看到其他可能性或 alternative.s
等了一段时间,除了使用local-storage,我没有得到任何解决方案。所以,我采取了混合方法。在我的方法中,我在实现它的浏览器上使用 navigator.permissions
,对于其他浏览器,我使用 localstorage
.
我正在使用 React,所以我的解决方案包括 React 代码,但这个想法仍然可以用于纯 javascript 或任何 javascript 框架。
我为此创建了一个自定义挂钩:
useGeoLocation.ts
import { useState, useEffect } from 'react';
interface Coordinates {
latitude: number;
longitude: number;
};
const useGeoLocation = (localStorageKey = 'is-location-granted') => {
const [shouldRequestLocation, setShouldRequestLocation] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<GeolocationPositionError>();
const [coords, setCoords] = useState<Coordinates>();
const onSuccess = (location: GeolocationPosition) => {
setLoading(false);
setCoords({
latitude: location.coords.latitude,
longitude: location.coords.longitude,
});
if (!('permissions' in navigator)) {
localStorage.setItem(localStorageKey, JSON.stringify(true));
}
}
const onError = (error: GeolocationPositionError) => {
setLoading(false);
setError(error);
}
useEffect(() => {
if ('permissions' in navigator) {
navigator.permissions.query({ name: 'geolocation' }).then((permissionStatus) => {
if (permissionStatus.state !== 'granted') {
setShouldRequestLocation(true);
}
});
} else {
const isLocationGranted = JSON.parse(localStorage.getItem(localStorageKey) || 'false');
if (!isLocationGranted) {
setShouldRequestLocation(true);
}
}
}, []);
useEffect(() => {
if(!('geolocation' in navigator)) {
const geoError = new GeolocationPositionError();
setError({
...geoError,
message: 'Geolocation not supported'
});
} else if (shouldRequestLocation) {
setLoading(true);
navigator.geolocation.getCurrentPosition(
onSuccess,
onError,
{ enableHighAccuracy: false, timeout: 10000, maximumAge: 18000000 },
);
}
}, [shouldRequestLocation]);
return { loading, error, coords };
};
export default useGeoLocation;
代码非常简单,但如果有人发现任何困难,请告诉我,我会相应地更新我的答案。
我的设置:
我有一些非常简单的代码:
const onSuccess = () => {
console.log('success');
}
const onError = () => {
console.log('error');
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
我的实际代码包含更多逻辑。但为简单起见,我只发布了所需的代码。
- 我第一次访问该页面时被要求获得许可。
- 让我们假设,我授予使用我的地理位置的权限。
success
打印到控制台。
目前一切顺利...
实际问题:
- 每次刷新页面时,我都会
success
登录到控制台。 - 其实我想要不一样的东西。当用户授予使用地理定位的访问权限时,我只想调用我的函数一次。
现在,如果用户阻止地理定位并且再次允许浏览器使用地理定位,那么在那个时候,success
应该被记录。但是在每次刷新时,它不应该记录 success
.
所以,我相信,允许按钮上应该有某种事件侦听器,但我没有看到任何地方提到它。
我的研究:
我不确定我的方向是否正确,但是...
在 MDN 文档 here 上,我可以看到有一个叫做 PermissionStatus.onchange
.
但它是实验性的,不支持 Internet Explorer、Safari 和 Safari iOS。
如果你们中有人使用过任何替代方案,那么我很乐意检查你的想法。
实际用例
我正在开发天气应用程序。要求是:
当用户登陆网站时,应该要求他获得地理定位许可(如果尚未授予)
一旦用户授予权限,他应该被带到可以查看他所在城市的天气详细信息的页面。
目前的问题是,每次我刷新页面时,它都会检测到用户的位置并将用户带到他的城市详细信息页面。这是不好的。这应该只发生一次,只有当用户授予对地理定位的访问权限时。
我的实际技术栈
- 反应
- 打字稿
更新:
我收到了一些将用户权限状态存储到本地存储的建议。
但是,如果我将权限存储在本地存储中,则会遇到一些问题。
我举个例子详细解释一下
部分直到一切正常:
- 如果用户授予读取其位置的权限。
- 然后我把他带到城市详情页面。
- 然后我保存在用户已授予权限的本地存储中。
- 现在如果用户刷新页面,那么一切似乎都正常。
当我遇到问题时:
- 现在用户进入 chrome 设置并删除我网站的位置权限。
- 然后用户刷新我的网站,他会看到一个弹出窗口,要求他提供位置权限。
- 如果他随后允许该权限,那么我将无法知道用户再次允许该权限,因为在我的本地存储中,我已经存储了位置授权。所以,我无法将他带到城市详细信息页面。
您可以将权限状态保存到本地存储,并在每次页面刷新时检查权限是否已更改:
const onSuccess = () => {
console.log('success');
if (localStorage.getItem("permission_status") !== "ok") {
// fire permission onchange event
// update local storage
}
}
const onError = () => {
console.log('error');
if (localStorage.getItem("permission_status") === "ok") {
// fire permission onchange event
// update local storage
}
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
我的建议不是保存用户的权限状态,而是在成功回调中保存用户的 GeolocationPosition
对象。
所以你可以比较对象而不是比较权限状态。
由于 macOS 浏览器不支持,您无法使用 navigator.permissions
,唯一的解决方案是保存坐标数据本身以供比较。
因此您的代码将如下所示:
const onSuccess = (pos) => {
if (localStorage.getItem("latitude") !== pos.coords.latitude ||
localStorage.getItem("longitude") !== pos.coords.longitude)
{
// fire permission onchange event
// update local storage
console.log('success');
}
}
const onError = () => {
console.log('error');
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
编辑 刚看到你对@Zeke Hernandez 的评论。这是独立于权限的解决方案,所以我认为它应该适合你。 我不知道你是如何渲染用户的城市详情页面,但我相信你会使用用户的位置数据来渲染页面,我们可以在成功回调中使用我们保存到本地存储的数据。 我没有看到其他可能性或 alternative.s
等了一段时间,除了使用local-storage,我没有得到任何解决方案。所以,我采取了混合方法。在我的方法中,我在实现它的浏览器上使用 navigator.permissions
,对于其他浏览器,我使用 localstorage
.
我正在使用 React,所以我的解决方案包括 React 代码,但这个想法仍然可以用于纯 javascript 或任何 javascript 框架。
我为此创建了一个自定义挂钩:
useGeoLocation.ts
import { useState, useEffect } from 'react';
interface Coordinates {
latitude: number;
longitude: number;
};
const useGeoLocation = (localStorageKey = 'is-location-granted') => {
const [shouldRequestLocation, setShouldRequestLocation] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<GeolocationPositionError>();
const [coords, setCoords] = useState<Coordinates>();
const onSuccess = (location: GeolocationPosition) => {
setLoading(false);
setCoords({
latitude: location.coords.latitude,
longitude: location.coords.longitude,
});
if (!('permissions' in navigator)) {
localStorage.setItem(localStorageKey, JSON.stringify(true));
}
}
const onError = (error: GeolocationPositionError) => {
setLoading(false);
setError(error);
}
useEffect(() => {
if ('permissions' in navigator) {
navigator.permissions.query({ name: 'geolocation' }).then((permissionStatus) => {
if (permissionStatus.state !== 'granted') {
setShouldRequestLocation(true);
}
});
} else {
const isLocationGranted = JSON.parse(localStorage.getItem(localStorageKey) || 'false');
if (!isLocationGranted) {
setShouldRequestLocation(true);
}
}
}, []);
useEffect(() => {
if(!('geolocation' in navigator)) {
const geoError = new GeolocationPositionError();
setError({
...geoError,
message: 'Geolocation not supported'
});
} else if (shouldRequestLocation) {
setLoading(true);
navigator.geolocation.getCurrentPosition(
onSuccess,
onError,
{ enableHighAccuracy: false, timeout: 10000, maximumAge: 18000000 },
);
}
}, [shouldRequestLocation]);
return { loading, error, coords };
};
export default useGeoLocation;
代码非常简单,但如果有人发现任何困难,请告诉我,我会相应地更新我的答案。