Skip to main content

BOM

Window

const selfWindow = window.self
const topWindow = window.top
const parentWindow = window.parent
const grandParentWindow = window.parent.parent
if (confirm('Are you sure?'))
alert('I\'m so glad you\'re sure!')
else
alert('I\'m sorry to hear you\'re not sure.')

const result = prompt('What is your name? ', 'James')
if (result !== null)
alert(`Welcome, ${result}`)

// 显示打印对话框
window.print()

// 显示查找对话框
window.find()

// 显式打印机
window.print()

弹窗有非常多的安全限制:

  • 禁止隐藏状态栏与地址栏.
  • 弹窗默认不能移动或缩放.
  • 只允许用户操作下 (鼠标/键盘) 创建弹窗.
  • 屏蔽弹窗.
const newWin = window.open(
'https://www.new.com/',
'newWindow',
'height=400,width=400,top=10,left=10,resizable=yes'
)
newWin.resizeTo(500, 500)
newWin.moveTo(100, 100)
alert(newWin.opener === window) // true
newWin.close()
alert(newWin.closed) // true

let blocked = false
try {
const newWin = window.open('https://www.new.com/', '_blank')
if (newWin === null)
blocked = true
} catch (ex) {
blocked = true
}
if (blocked)
alert('The popup was blocked!')

Location

属性描述
hash设置或返回从井号 (#) 开始的 URL (锚)
host设置或返回主机名和当前 URL 的端口号
hostname设置或返回当前 URL 的主机名
href设置或返回完整的 URL
pathname设置或返回当前 URL 的路径部分
port设置或返回当前 URL 的端口号
protocol设置或返回当前 URL 的协议
search设置或返回从问号 (?) 开始的 URL (查询部分)
username设置或返回域名前指定的用户名
password设置或返回域名前指定的密码
origin返回 URL 的源地址
function getQueryStringArgs(location) {
// 取得没有开头问号的查询字符串
const qs = location.search.length > 0 ? location.search.substring(1) : ''
// 保存数据的对象
const args = {}

// 把每个参数添加到 args 对象
for (const item of qs.split('&').map(kv => kv.split('='))) {
const name = decodeURIComponent(item[0])
const value = decodeURIComponent(item[1])

if (name.length)
args[name] = value
}

return args
}
window.location.assign('https://www.new.com')
window.location = 'https://www.new.com'
window.location.href = 'https://www.new.com'
window.location.replace('https://www.new.com') // No new history
window.location.reload() // 重新加载, 可能是从缓存加载
window.location.reload(true) // 重新加载, 从服务器加载
window.addEventListener(
'hashchange',
(event) => {
// event.oldURL
// event.nweURL
if (window.location.hash === '#someCoolFeature')
someCoolFeature()
},
false
)

navigator 对象包含以下接口定义的属性和方法:

  • NavigatorID.
  • NavigatorLanguage.
  • NavigatorOnLine.
  • NavigatorContentUtils.
  • NavigatorStorage.
  • NavigatorStorageUtils.
  • NavigatorConcurrentHardware.
  • NavigatorPlugins.
  • NavigatorUserMedia.
Property/Method
batteryBatteryManager (Battery Status API)
clipboardClipboard API
connectionNetworkInformation (Network Information API)
cookieEnabledBoolean, 是否启用了 cookie
credentialsCredentialsContainer (Credentials Management API)
deviceMemory单位为 GB 的设备内存容量
doNotTrack用户的不跟踪 (do-not-track) 设置
geolocationGeolocation (Geolocation API)
hardwareConcurrency设备的处理器核心数量
language浏览器的主语言
languages浏览器偏好的语言数组
locksLockManager (Web Locks API)
mediaCapabilitiesMediaCapabilities (Media Capabilities API)
mediaDevices可用的媒体设备
maxTouchPoints设备触摸屏支持的最大触点数
onLineBoolean, 表示浏览器是否联网
pdfViewerEnabledBoolean, 是否启用了 PDF 功能
permissionsPermissions (Permissions API)
serviceWorkerServiceWorkerContainer
storageStorageManager (Storage API)
userAgent浏览器的用户代理字符串 (默认只读)
vendor浏览器的厂商名称
webdriver浏览器当前是否被自动化程序控制
xrXRSystem (WebXR Device API)
registerProtocolHandler()将一个网站注册为特定协议的处理程序
sendBeacon()异步传输一些小数据
share()当前平台的原生共享机制
vibrate()触发设备振动

Web Online API

const connectionStateChange = () => console.log(navigator.onLine)
window.addEventListener('online', connectionStateChange)
window.addEventListener('offline', connectionStateChange)
// 设备联网时:
// true
// 设备断网时:
// false

Web Connection API

const downlink = navigator.connection.downlink
const downlinkMax = navigator.connection.downlinkMax
const rtt = navigator.connection.rtt
const type = navigator.connection.type // wifi/bluetooth/cellular/ethernet/mixed/unknown/none.
const networkType = navigator.connection.effectiveType // 2G - 5G.
const saveData = navigator.connection.saveData // Boolean: Reduced data mode.

navigator.connection.addEventListener('change', changeHandler)

Web Protocol Handler API

navigator.registerProtocolHandler(
'mailto',
'http://www.somemailclient.com?cmd=%s',
'Some Mail Client'
)

Web Battery Status API

navigator.getBattery().then((battery) => {
// 添加充电状态变化时的处理程序
const chargingChangeHandler = () => console.log(battery.charging)
battery.addEventListener('chargingchange', chargingChangeHandler)
// 添加充电时间变化时的处理程序
const chargingTimeChangeHandler = () => console.log(battery.chargingTime)
battery.addEventListener('chargingtimechange', chargingTimeChangeHandler)
// 添加放电时间变化时的处理程序
const dischargingTimeChangeHandler = () =>
console.log(battery.dischargingTime)
battery.addEventListener(
'dischargingtimechange',
dischargingTimeChangeHandler
)
// 添加电量百分比变化时的处理程序
const levelChangeHandler = () => console.log(battery.level * 100)
battery.addEventListener('levelchange', levelChangeHandler)
})

Web Storage Estimate API

navigator.storage.estimate().then((estimate) => {
console.log(((estimate.usage / estimate.quota) * 100).toFixed(2))
})

Web Geolocation API

if (window.navigator.geolocation) {
// getCurrentPosition第三个参数为可选参数
navigator.geolocation.getCurrentPosition(locationSuccess, locationError, {
// 指示浏览器获取高精度的位置, 默认为false
enableHighAccuracy: true,
// 指定获取地理位置的超时时间, 默认不限时, 单位为毫秒
timeout: 5000,
// 最长有效期, 在重复获取地理位置时, 此参数指定多久再次获取位置.
maximumAge: 3000,
})
} else {
alert('Your browser does not support Geolocation!')
}

locationError 为获取位置信息失败的回调函数, 可以根据错误类型提示信息:

function locationError(error) {
switch (error.code) {
case error.TIMEOUT:
showError('A timeout occurred! Please try again!')
break
case error.POSITION_UNAVAILABLE:
showError('We can\'t detect your location. Sorry!')
break
case error.PERMISSION_DENIED:
showError('Please allow geolocation access for this to work.')
break
case error.UNKNOWN_ERROR:
showError('An unknown error occurred!')
break
default:
throw new Error('Unsupported error!')
}
}

locationSuccess 为获取位置信息成功的回调函数, 返回的数据中包含经纬度等信息:

  • position.timestamp.
  • position.coords:
    • latitude: 维度.
    • longitude: 经度.
    • accuracy.
    • altitude: 海拔高度.
    • altitudeAccuracy.

结合 Google Map API 即可在地图中显示当前用户的位置信息:

function locationSuccess(position) {
const coords = position.coords
const latlng = new google.maps.LatLng(
// 维度
coords.latitude,
// 精度
coords.longitude
)
const myOptions = {
// 地图放大倍数
zoom: 12,
// 地图中心设为指定坐标点
center: latlng,
// 地图类型
mapTypeId: google.maps.MapTypeId.ROADMAP,
}

// 创建地图并输出到页面
const myMap = new google.maps.Map(document.getElementById('map'), myOptions)

// 创建标记
const marker = new google.maps.Marker({
// 标注指定的经纬度坐标点
position: latlng,
// 指定用于标注的地图
map: myMap,
})

// 创建标注窗口
const infoWindow = new google.maps.InfoWindow({
content: `您在这里<br/>纬度: ${coords.latitude}<br/>经度: ${coords.longitude}`,
})

// 打开标注窗口
infoWindow.open(myMap, marker)
}
navigator.geolocation.watchPosition(
locationSuccess,
locationError,
positionOption
)

navigator.userAgent 特别复杂:

  • 历史兼容问题: Netscape -> IE -> Firefox -> Safari -> Chrome -> Edge.
  • 每一个新的浏览器厂商必须保证旧网站的检测脚本能正常识别自家浏览器, 从而正常打开网页, 导致 navigator.userAgent 不断变长.
  • UserAgent Data Parser
console.log(navigator.userAgent)
// 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)
// Chrome/101.0.4922.0 Safari/537.36 Edg/101.0.1198.0'

Screen

浏览器窗口外面的客户端显示器的信息:

Property
availHeight屏幕像素高度减去系统组件高度 (只读)
availWidth屏幕像素宽度减去系统组件宽度 (只读)
colorDepth表示屏幕颜色的位数: 多数系统是 32 (只读)
height屏幕像素高度
width屏幕像素宽度
pixelDepth屏幕的位深 (只读)
orientationScreen Orientation API 中屏幕的朝向
const screen = window.screen

console.log(screen.colorDepth) // 24
console.log(screen.pixelDepth) // 24

// 垂直看
console.log(screen.orientation.type) // portrait-primary
console.log(screen.orientation.angle) // 0
// 向左转
console.log(screen.orientation.type) // landscape-primary
console.log(screen.orientation.angle) // 90
// 向右转
console.log(screen.orientation.type) // landscape-secondary
console.log(screen.orientation.angle) // 270

全屏 API:

function toggleFullscreen() {
const elem = document.querySelector('video')

if (document.fullscreenElement) {
document
.exitFullscreen()
.then(() => console.log('Document Exited from Full screen mode'))
.catch(err => console.error(err))
} else {
elem
.requestFullscreen()
.then(() => {})
.catch((err) => {
alert(
`Error occurred while switch into fullscreen mode: ${err.message} (${err.name})`
)
})
}
}

document.onclick = function (event) {
if (document.fullscreenElement) {
document
.exitFullscreen()
.then(() => console.log('Document Exited from Full screen mode'))
.catch(err => console.error(err))
} else {
document.documentElement
.requestFullscreen({ navigationUI: 'show' })
.then(() => {})
.catch((err) => {
alert(
`Error occurred while switch into fullscreen mode: ${err.message} (${err.name})`
)
})
}
}

History

History Navigation

const history = window.history

// 后退一页
history.go(-1)
// 前进一页
history.go(1)
// 前进两页
history.go(2)
// 导航到最近的 new.com 页面
history.go('new.com')
// 导航到最近的 example.net 页面
history.go('example.net')
// 后退一页
history.back()
// 前进一页
history.forward()

if (history.length === 1)
console.log('这是用户窗口中的第一个页面')

if (history.scrollRestoration)
history.scrollRestoration = 'manual'

History State Management

const history = window.history

const stateObject = { foo: 'bar' }
history.pushState(stateObject, 'My title', 'baz.html')

history.replaceState({ newFoo: 'newBar' }, 'New title') // No new history state.

window.addEventListener('popstate', (event) => {
const state = event.state

if (state) {
// 第一个页面加载时状态是 null
processState(state)
}
})

Browser Compatibility

User Agent Detection

class BrowserDetector {
constructor() {
// 测试条件编译
// IE6~10 支持

this.isIE_Gte6Lte10 = /* @cc_on!@ */ false
// 测试 documentMode
// IE7~11 支持
this.isIE_Gte7Lte11 = !!document.documentMode
// 测试 StyleMedia 构造函数
// Edge 20 及以上版本支持
this.isEdge_Gte20 = !!window.StyleMedia
// 测试 Firefox 专有扩展安装 API
// 所有版本的 Firefox 都支持
this.isFirefox_Gte1 = typeof InstallTrigger !== 'undefined'
// 测试 chrome 对象及其 webstore 属性
// Opera 的某些版本有 window.chrome, 但没有 window.chrome.webstore
// 所有版本的 Chrome 都支持
this.isChrome_Gte1 = !!window.chrome && !!window.chrome.webstore
// Safari 早期版本会给构造函数的标签符追加 "Constructor"字样, 如:
// window.Element.toString(); // [object ElementConstructor]
// Safari 3~9.1 支持
this.isSafari_Gte3Lte9_1 = /constructor/i.test(window.Element)
// 推送通知 API 暴露在 window 对象上
// 使用 IIFE 默认参数值以避免对 undefined 调用 toString()
// Safari 7.1 及以上版本支持
this.isSafari_Gte7_1 = (({ pushNotification = {} } = {}) =>
pushNotification.toString() === '[object SafariRemoteNotification]')(
window.safari
)
// 测试 addons 属性
// Opera 20 及以上版本支持
this.isOpera_Gte20 = !!window.opr && !!window.opr.addons
}

isIE() {
return this.isIE_Gte6Lte10 || this.isIE_Gte7Lte11
}

isEdge() {
return this.isEdge_Gte20 && !this.isIE()
}

isFirefox() {
return this.isFirefox_Gte1
}

isChrome() {
return this.isChrome_Gte1
}

isSafari() {
return this.isSafari_Gte3Lte9_1 || this.isSafari_Gte7_1
}

isOpera() {
return this.isOpera_Gte20
}
}

Browser Feature Detection

不使用特性/浏览器推断, 往往容易推断错误 (且会随着浏览器更新产生新的错误).

// 检测浏览器是否支持 Netscape 式的插件
const hasNSPlugins = !!(navigator.plugins && navigator.plugins.length)
// 检测浏览器是否具有 DOM Level 1 能力
const hasDOM1 = !!(
document.getElementById
&& document.createElement
&& document.getElementsByTagName
)

// 特性检测
if (document.getElementById)
element = document.getElementById(id)