使用“事件监听/链式事件处理方式”实现window.onload同时调用多个函数

本文介绍如何在HTML页面加载完成后正确地运行多个函数,解决了window.onload只能被使用一次的问题。通过事件监听器和链式事件处理方式实现,确保所有函数都能按预期执行。

window.onload的作用是在HTML页面加载完成后,再运行被调用的函数。这样可以避免一个现象就是当要运行的函数里包含某个HTML页面元素(如document.getElmentByID)而当函数运行时,该元素却还没被浏览器加载,则此时会因找不到对应元素而出错。

      但window.onload在同个页面里只能被使用一次,这就导致了假如你写了如下代码:

      window.onload=firstFunction;

      window.onload=secondFunction;

      那么最终secondFunction会覆盖掉firstFunction,导致无法成功调用firstFunction。

      一般情况下解决这个问题采用两类方式,一类是用事件监听器,另一类是用链式事件处理方式。事件监听器会是优先考虑的方式,但由于一些老式浏览器可能无法识别事件监听语句,因此我们在实际操作中可能也需要为用户提供备选的链式事件处理方式。现在开始贴代码:

//实现用window.onload同时调用多个函数,调用顺序是从后往前。前三种用监听器实现,后一种用链式事件处理方式实现。注意:监听器W3C标准方法是addEventListener(非IE浏览器采用此方法),但IE浏览器用attachEvent。
addLoad(firstFunction);
addLoad(secondFunction);
addLoad(thirdFunction);

function addLoad(fn)
{
     if (typeof window.addEventListener != "undefined")//判断浏览器是否能够识别window.addEventListener,假如可以,则执行以下代码
          {
                 window.addEventListener("load",fn,false);
           }
      else if (typeof document.addEventListener != "undefined")//某些浏览器无法识别window.addEventListener,只能识别document.addEventListener,因此要增加这一步判断
      {
             document.addEventListener("load",fn,false);
       }
      else if (typeof window.attachEvent != "undefined")//前面两种都无法识别,则判定是否可以识别window.attachEvent
       {
            window.attachEvent("onload",fn);
      }
      else//前三种都无法识别,则用这最后一种:老式链式事件处理方式
       {
            var oldfn=window.onload;
           if (typeof window.onload != "function")
             {
                   window.onload=fn;
            }
            else
             {
                   window.onload=function()
                  {
                         oldfn();
                         fn();
                   };
             }
     }
}


function firstFunction()//最先的函数最后运行
{
      alert("这是第一个函数")
}

function secondFunction()//第二个运行
{
      alert("这是第二个函数")
}

function thirdFunction()//最后的函数最先运行
{
      alert("这是第三个函数")
}

      程序运行的结果是先后弹出三个对话框。

 

<template> <div ref="targetRef" class="app-no-padding-container"> <!-- 地图容器:高度由ResizeObserver动态计算 --> <div id="allmap" :style="{ height: `${elementHeight}px`, width: '100%' }"></div> </div> </template> <script setup> import { onMounted, ref, onUnmounted, watch } from "vue"; import { useResizeObserver } from "@/utils/use-resize-observer"; // ------------------------------ // 对外暴露配置(父组件通过Props传递) // ------------------------------ const props = defineProps({ // 初始中心点坐标(父组件可自定义) center: { type: Array, default: () => [104.0426, 30.5561], // 默认成都坐标 [lng, lat] }, // 初始缩放级别(父组件可自定义) zoom: { type: Number, default: 11, }, // 是否开启滚轮缩放(父组件可控制) enableScrollWheelZoom: { type: Boolean, default: true, }, // 是否开启拖拽(父组件可控制) enableDragging: { type: Boolean, default: true, }, // 地图倾斜角度 tilt: { type: Number, default: 35, }, // 是否使用轨迹回放 isTrack: { type: Boolean, default: false, }, // 轨迹经纬度数组 trackData: { type: Array, default: () => [], }, }); // ------------------------------ // 对外传递事件(父组件可监听) // ------------------------------ const emit = defineEmits([ "map-loaded", // 地图加载完成(传递地图实例) "map-click", // 地图点击事件(传递点击坐标) "map-resize", // 地图容器 resize 事件(传递新宽高) "track-playing", //轨迹回放事件 "track-finished", //轨迹完成事件 ]); // ------------------------------ // 内部状态与工具 // ------------------------------ // ResizeObserver:动态计算容器高度 const { targetRef, elementHeight } = useResizeObserver(); // 地图实例(内部维护,对外暴露) const mapInstance = ref(null); // 百度地图命名空间(3.0+版本为BMapGL,避免混淆) const BMapGL = ref(null); // 轨迹命名空间 const track = ref(null); // ------------------------------ // 地图初始化核心逻辑 // ------------------------------ // 加载百度地图API脚本// 加载地图依赖插件 + 地图主脚本 const loadMapScript = () => { // 验证是否已加载(注意 three.js 暴露的是大写 THREE) if (window.BMapGL && window.BMapGL.TrackAnimation && window.THREE) { BMapGL.value = window.BMapGL; initMap(); return; } // 插件列表(顺序必须严格:three.js → GLTFLoader → 轨迹插件) const plugins = [ "https://unpkg.com/three@0.126.0/build/three.min.js", // 1. 核心库(暴露 THREE) "https://unpkg.com/three@0.126.0/examples/js/loaders/GLTFLoader.js", // 2. 依赖 THREE "https://unpkg.com/@bmapgl-plugin/track", "//mapopen-pub-jsapi.bj.bcebos.com/jsapiGlgeo/track.js", ]; // 链式加载函数(确保按顺序加载) const loadPlugin = (index) => { if (index >= plugins.length) { // 所有插件加载完成,加载地图主脚本 loadBaiduMapMainScript(); return; } const pluginUrl = plugins[index]; const script = document.createElement("script"); script.type = "text/javascript"; script.src = pluginUrl; // 加载成功回调 script.onload = () => { console.log(`插件加载成功:${pluginUrl}`); // 验证 three.js 是否正确暴露 THREE(仅在加载第一个插件时检查) if (index === 0 && !window.THREE) { console.error("three.js 加载失败,未找到 THREE 全局对象"); return; // 终止后续加载 } // 加载下一个插件 loadPlugin(index + 1); }; // 加载失败回调 script.onerror = () => { console.error(`插件加载失败:${pluginUrl}`); // 若 three.js 加载失败,直接终止(后续插件依赖它) if (index === 0) { emit("map-loaded", { success: false, error: "three.js 加载失败,无法继续" }); } }; document.body.appendChild(script); }; // 从第一个插件开始加载(链式执行) loadPlugin(0); // 加载百度地图主脚本(逻辑不变) const loadBaiduMapMainScript = () => { const mapScript = document.createElement("script"); mapScript.type = "text/javascript"; mapScript.className = "loadmap"; mapScript.src = `https://api.map.baidu.com/getscript?v=1.0&type=webgl&ak=98RJrQoJ9zhIsMGF5ykJjDMlotBMSy5E`; mapScript.onload = () => { BMapGL.value = window.BMapGL; initMap(); // 清理旧脚本 const oldMapScripts = document.getElementsByClassName("loadmap"); Array.from(oldMapScripts).forEach((el) => { if (el !== mapScript) document.body.removeChild(el); }); }; mapScript.onerror = () => { console.error("百度地图API加载失败"); emit("map-loaded", { success: false, error: "API加载失败" }); }; document.body.appendChild(mapScript); }; }; // 初始化地图(API加载完成后执行) const initMap = () => { if (!BMapGL.value) return; console.log(window); try { // 1. 创建地图实例(绑定容器) const map = new BMapGL.value.Map("allmap", { style: "grayed-out", displayOptions: { indoor: false, poiText: false, poiIcon: false, building: false, }, }); mapInstance.value = map; // 2. 应用父组件传递的配置(中心点、缩放级别、城市) const centerPoint = new BMapGL.value.Point(props.center[0], props.center[1]); map.centerAndZoom(centerPoint, props.zoom); // 3. 应用交互配置(滚轮缩放、拖拽) // 滚轮缩放:props为true时开启 if (props.enableScrollWheelZoom) { map.enableScrollWheelZoom(true); } // 拖拽:props为true时开启 if (props.enableDragging) { map.enableDragging(true); } //设置地图倾斜角度 if (props.tilt) { map.setTilt(props.tilt); } // 生成轨迹实例 if (props.isTrack) { track.value = new window.Track.View(map, { lineLayerOptions: { style: { strokeWeight: 18, strokeLineJoin: "round", strokeLineCap: "round", }, }, }); } // 4. 绑定地图事件(传递给父组件) bindMapEvents(map); // 5. 通知父组件:地图加载完成(传递地图实例和命名空间) emit("map-loaded", { success: true, map: mapInstance.value, // 原生地图实例(父组件可直接调用API) BMapGL: BMapGL.value, // 百度地图命名空间(父组件可创建Marker/Polyline等) }); } catch (error) { console.error("地图初始化失败:", error); emit("map-loaded", { success: false, error: error.message }); } }; //初始化轨迹 const trackLine = ref(null); function initTrack() { // 1. 容错:确保轨迹视图、父组件轨迹数据都存在 if (!track.value || !props.trackData || props.trackData.length === 0) { console.warn("轨迹视图未初始化或轨迹数据为空,无法创建轨迹"); return; } const tempTrackData = ref([]); const colorOffset = ref([]); for (const item of props.trackData) { const point = new window.BMapGL.Point(item.longittude, item.latitude); const trackPoint = new window.Track.TrackPoint(point); tempTrackData.value.push(trackPoint); const choose = [0.9, 0.5, 0.1]; const color = choose[Math.floor(Math.random() * choose.length)]; colorOffset.value.push(color); } // 创建本地轨迹实例 trackLine.value = new window.Track.LocalTrack({ trackPath: tempTrackData.value, duration: 60, style: { sequence: true, marginLength: 32, arrowColor: "#fff", strokeTextureUrl: "//mapopen-pub-jsapi.bj.bcebos.com/jsapiGlgeo/img/down.png", strokeTextureWidth: 64, strokeTextureHeight: 32, traceColor: [27, 142, 236], }, linearTexture: [ [0, "#f45e0c"], [0.5, "#f6cd0e"], [1, "#2ad61d"], ], gradientColor: colorOffset, }); // 监听轨迹线状态变化并自动动态视口适配 trackLine.value.on(window.Track.LineCodes.STATUS, (status) => { switch (status) { case window.Track.StatusCodes.PLAY: //播放中 case window.Track.StatusCodes.RESUME: //从暂停恢复播放 break; case window.Track.StatusCodes.INIT: //轨迹初始化完成 case window.Track.StatusCodes.PAUSE: //轨迹暂停 case window.Track.StatusCodes.STOP: //轨迹停止 case window.Track.StatusCodes.FINISH: { //轨迹播放完成 const box = trackLine.value.getBBox(); if (box) { const bounds = [ new window.BMapGL.Point(box[0], box[1]), new window.BMapGL.Point(box[2], box[3]), ]; map.setViewport(bounds); } break; } default: break; } }); track.value.addTrackLine(trackLine.value); track.value.focusTrack(trackLine.value); //创建移动图标 const movePoint = new window.Track.GroundPoint({ point: tempTrackData.value[0].getPoint(), style: { url: "//mapopen-pub-jsapi.bj.bcebos.com/jsapiGlgeo/img/car.png", level: 18, scale: 1, size: new BMapGL.value.Size(16, 32), anchor: new BMapGL.value.Size(0.5, 0.5), }, }); //移动图标绑定监听事件 movePoint.addEventListener(window.Track.MapCodes.CLICK, (e) => { console.log("Track.GroundPoint.click", e); }); movePoint.addEventListener(window.Track.MapCodes.MOUSE_OVER, (e) => { console.log("Track.GroundPoint.MOUSE_OVER", e); }); movePoint.addEventListener(window.Track.MapCodes.MOUSE_OUT, (e) => { console.log("Track.GroundPoint.MOUSE_OUT", e); }); trackLine.value.setMovePoint(movePoint); } // 清除现有轨迹(核心新增方法) const clearTrack = () => { if (!track.value || !trackLine.value) return; try { // 1. 停止轨迹动画 if (trackLine.value.stopAnimation) { trackLine.value.stopAnimation(); } // 2. 移除轨迹线 track.value.removeTrackLine(trackLine.value); // 3. 销毁轨迹线实例(释放资源) if (trackLine.value.destroy) { trackLine.value.destroy(); } // 4. 重置轨迹线引用 trackLine.value = null; } catch (error) { console.error("清除轨迹失败:", error); } }; // 深度监听trackData变化(核心新增逻辑) watch( () => props.trackData, (newData) => { // 地图和轨迹视图初始化完成后才处理 if (mapInstance.value && track.value) { // 先清除原有轨迹,再初始化新轨迹 clearTrack(); // 新数据不为空时才初始化 if (newData && newData.length > 0) { initTrack(); } } }, { deep: true, immediate: false } // deep: 深度监听数组和对象变化 ); // 绑定地图事件(传递给父组件) const bindMapEvents = (map) => { // 地图点击事件:传递点击的经纬度 map.addEventListener("click", (e) => { emit("map-click", { lng: e.latlng.lng, lat: e.latlng.lat, point: e.latlng, // 原生Point对象 }); }); // 地图容器resize事件:传递新高度(配合ResizeObserver) // watch(elementHeight, (newHeight) => { // emit("map-resize", { height: newHeight, width: "100%" }); // }); }; // ------------------------------ // 对外暴露组件内部方法(父组件可调用) // ------------------------------ defineExpose({ // 手动设置地图中心点(父组件可调用) setCenter: (lng, lat) => { if (!mapInstance.value || !BMapGL.value) return; const point = new BMapGL.value.Point(lng, lat); mapInstance.value.centerAndZoom(point, props.zoom); }, // 手动添加标记(父组件可调用) addMarker: (lng, lat, options = {}) => { if (!mapInstance.value || !BMapGL.value) return null; const point = new BMapGL.value.Point(lng, lat); const marker = new BMapGL.value.Marker(point, options); mapInstance.value.addOverlay(marker); return marker; // 返回标记实例,父组件可后续操作(如绑定点击事件) }, // 获取当前地图实例(父组件可直接操作) getMapInstance: () => mapInstance.value, //轨迹开始回放 startAnimation: () => { trackLine.value.startAnimation(); }, //轨迹停止回放 stopAnimation: () => { trackLine.value.stopAnimation(); }, //轨迹继续回放 pauseAnimation: () => { trackLine.value.pauseAnimation(); }, //轨迹重置 resumeAnimation: () => { trackLine.value.resumeAnimation(); }, }); // ------------------------------ // 组件生命周期 // ------------------------------ // 组件挂载:加载地图 onMounted(() => { loadMapScript(); }); // 组件卸载:清理地图资源(避免内存泄漏) onUnmounted(() => { if (mapInstance.value) { // 清除所有覆盖物(Marker、轨迹等) mapInstance.value.clearOverlays(); // 销毁地图实例 mapInstance.value.destroy(); mapInstance.value = null; } // 清理轨迹资源 clearTrack(); if (track.value && track.value.destroy) { track.value.destroy(); track.value = null; } // 移除地图API脚本 const oldScripts = document.getElementsByClassName("loadmap"); Array.from(oldScripts).forEach((el) => document.body.removeChild(el)); }); </script> <style scoped> #allmap { transition: height 0.3s ease; } </style> 为什么没有显示轨迹线
10-18
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值