高德地图轨迹回放/轨迹播放

前言

本篇文章主要介绍高德地图的轨迹回放或播放的实现过程,是基于vue2实现的功能,同时做一些改动也是能够适配vue3的。其中播放条是用的是element UI中的el-slider组件,包括使用到的图标也是element UI自带的。可以实现轨迹的播放、暂停、停止、播放倍数,以及播放拖拽,涉及到的高德地图的相关权限申请,这里就不再赘述,好了,废话不多说,效果图附上。

效果图 


一、地图初始化

首先,需要在组件dom加载完毕后初始化地图,这里小谭直接用的new AMap.Map方法进行初始化,需要在index.html引入高德的服务。

<script src="https://webapi.amap.com/maps?v=2.0&key=你的key"></script>

其次,在引入高德服务之后,需要在单独引入高德AMapUI 组件库,因为轨迹播放是基于该组件库实现的,引入示例:

<!--引入UI组件库(1.1版本) -->
<script src="//webapi.amap.com/ui/1.1/main.js"></script>

最后,就可以进行初始化地图了,注意需要在组件dom加载完毕才能进行初始化!其中this.map是地图实例,附上代码:

 this.map = new AMap.Map('myMap', {
            zoom: 10, //级别
            center:[120.209758, 30.246809], //中心点坐标 默认在杭州
 });

二、轨迹插件初始化

在地图初始化完成之后,可以引入一些需要的插件,这里就不再过多赘述,我们直接引入AMapUI,我们这里用到的是PathSimplifier模块,故只需要引入该模块即可,附上代码:

//加载PathSimplifier,loadUI的路径参数为模块名中 'ui/' 之后的部分
new AMapUI.load(['ui/misc/PathSimplifier'], PathSimplifier => {
    if (!PathSimplifier.supportCanvas) {
        alert('当前环境不支持 Canvas!');
        return;
    }
    if (this.pathList?.length) {
        //启动页面
        this.initPage(PathSimplifier);
    }
});

其中,涉及到的this.pathList是我这边后端返回坐标点信息,this.pathList结构如下:

this.pathList = [
    [
        120.79580028, // 经度
        30.03570354 // 纬度
    ],
    ...
    
];

this.initPage方法如下,需要注意的是,方法内声明的content是轨迹播放时展示的车辆图标,如果不需要可以删掉,PathSimplifier中的配置请参照高德地图轨迹展示的开发文档,还有方法最后调用的this.cruiseInit方法已经放到下一部分了。

initPage(PathSimplifier) {
    let content = PathSimplifier.Render.Canvas.getImageContent(
        '/img/car1.png',
        () => {
            //图片加载成功,重新绘制一次
            this.pathSimplifierIns.renderLater();
        },
        function onerror(e) {
            this.$message({ type: 'error', message: '图片加载失败!' });
        }
    );
    this.pathSimplifierIns = new PathSimplifier({
        zIndex: 100,
        map: this.map,
        getPath: function (pathData, pathIndex) {
            return pathData.path;
        },
        renderOptions: {
            //轨迹线的样式
            getPathStyle: (pathItem, zoom) => {
                return {
                    pathLineStyle: {
                        strokeStyle: "red",
                        lineWidth: 6,
                        dirArrowStyle: true,
                    },
                };
            },
            pathNavigatorStyle: {
                initRotateDegree: 180,
                width: 20,
                height: 35,
                autoRotate: true,
                content,
            },
        },
    });
    this.cruiseInit(); //巡航器初始化
}

三、巡航器初始化

巡航器初始化方法this.cruiseInit代码如下:

cruiseInit() {
    let pathSimplifierIns = [{ path: this.pathList, color: '#28F' }];
    this.pathSimplifierIns.setData(pathSimplifierIns);
    this.pointSum = 0;
    pathSimplifierIns.forEach((item, index) => {
        this.pointSum += item.path.length;
    });

    this.marksIndex = marksIndex;
    this.cruiseStop();//如果已经存在巡航器,则停止播放
}

其中this.pointSum是为了记录巡航器的最终点数,方便对应到播放条的最大值。


四、巡航器的播放暂停等功能

巡航器的播放、暂停以及倍数的方法如下:

// 创建一个巡航器
createdCruise(index) {
    // 判断是否传入index
    let cruiseIndex;
    if (index != undefined) {
        cruiseIndex = index;
        this.cruiseIndex = index;
    } else {
        cruiseIndex = this.cruiseIndex;
    }
    let cruise = this.pathSimplifierIns.createPathNavigator(
        cruiseIndex, //关联第index条轨迹
        {
            loop: false, //循环播放
            speed: this.speedList[this.speedValue].speed, //速度
        }
    );

    if (this.cruise) {
        // 清空走过的路线
        this.cruise.destroy();
        this.cruise = null;
    }

    return cruise;
},
// 开始播放
cruiseStart() {
    this.isPlay = true;

    if (this.cruise && !this.cruise.isCursorAtPathEnd() && !this.cruise.isCursorAtPathStart() && !this.isComplete) {
        // 路段未开始并且没有结束的时候 暂停恢复动画 并且动画没有完成的时候
        this.cruise.resume();
        return;
    }
    this.isComplete = false;
    if (this.cruiseIndex == 0) {
        this.cruiseStop();
        return;
    }

    this.cruise = this.createdCruise();

    // 判断是否传入初始坐标
    if (this.startPoint) {
        this.cruise.start(this.startPoint);
        this.startPoint = 0;
    } else {
        this.cruise.start();
    }
    this.cruise.on('move', e => {
        let idx = this.cruise.cursor.idx;
        let { address, gpsTime, speed } = this.pathList[idx];
        let trackAddress = {
            address,
            gpsTime,
            speed,
        };
        this.$emit('changeData', 'trackAddress', trackAddress);
        let [min, max] = this.marksIndex[this.cruiseIndex];
        this.sliderValue = idx + min;
    });
    // 巡航完成事触发
    this.cruise.on('pause', () => {
        if (this.cruise && this.cruise.isCursorAtPathEnd()) {
            this.cruiseStart();
        }
    });
},

// 暂停播放
cruisePause() {
    this.cruise.pause();
    this.isPlay = false;
},
// 停止播放
cruiseStop() {
    if (this.cruise) {
        // 清空走过的路线
        this.cruise.destroy();
    }
    // 停止播放
    this.isPlay = false;
    this.isComplete = true;
    this.cruiseIndex = -1;
    // 为重新播放准备
    this.cruise = this.createdCruise();
    this.cruiseIndex = -1;
    this.sliderValue = 0;
},
// 速度改变
speedChange() {
    if (this.speedValue == this.speedList.length - 1) {
        this.speedValue = 0;
    } else {
        this.speedValue++;
    }
    this.cruise.setSpeed(this.speedList[this.speedValue].speed);
},

到这里巡航器的基础功能已经实现,还有一部分关于播放器调整对应轨迹改变,这里我们要用的监听器,即vue的watch属性:

watch: {
    sliderValue(val) {
        // 正在播放禁止拖拽播放器
        if (!this.cruise || this.isPlay) return;
        this.cruise.moveToPoint(val);
        this.startPoint = val;
        this.pathSimplifierIns.render();
    },
},

五、变量声明以及HTML结构

其中使用到的变量有这些:

data() {
    return {    
        // 地图实例
        map: null,
        cruise: null, //巡航器实例
        cruiseIndex: -1, // 当前播放轨迹下标
        pathSimplifierIns: null, //轨迹实例
        isPlay: false, //是否播放
        isComplete: true, //是否完成
        pointSum: 0, //播放器总数
        sliderValue: 0, //播放器当前数
        startPoint: 0, //下次播放轨迹从当前值开始
        marksIndex: {}, //每段路的起止坐标
        pathList: [],// 轨迹坐标
        speedValue: 3,// 当前播放速度下标
        // 速度列表,可自定义配置
        speedList: [
            { value: 0.5, speed: 100 },
            { value: 1, speed: 200 },
            { value: 2, speed: 400 },
            { value: 4, speed: 1600 },
            { value: 8, speed: 12800 },
            { value: 16, speed: 25600 },
        ],
    };
},

HTML结构:

<template>
    <div class="workTrack">
        <div id="myMap"></div>
        <div class="sliderBar" v-show="pathList.length">
            <span @click="cruiseStart()" v-if="!isPlay">
                <i class="el-icon-video-play"></i>
            </span>
            <span @click="cruisePause" v-else>
                <i class="el-icon-video-pause"></i>
            </span>
            <span @click="cruiseStop">
                <i class="el-icon-error"></i>
            </span>
            <el-slider :disabled="isPlay" v-model="sliderValue" :max="pointSum" :show-tooltip="false"></el-slider>
            <b @click="speedChange">
                <i class="el-icon-d-arrow-right"></i>
                <span>×{{ speedList[speedValue].value }}</span>
            </b>
        </div>
    </div>
</template>

css:

.workTrack {
    width: 100%;
    position: relative;
    height: 100%;
    #myMap {
        width: 100%;
        height: 100%;
    }
    .sliderBar {
        position: absolute;
        bottom: 30px;
        user-select: none;
        width: 100%;
        padding: 10px 2%;
        background-color: #00000064;
        border-radius: 400px;
        backdrop-filter: blur(5px);
        z-index: 99;
        width: 80%;
        right: 0;
        left: 0;
        margin: auto;
        display: flex;
        justify-content: center;
        align-items: center;
        .el-slider {
            flex: 1;
            transform: translateY(1px);
            margin: 0 15px;
        }
        ::v-deep .el-slider__runway {
            pointer-events: none;
            background-color: #00000021;
            margin: 0;
            .el-slider__bar {
                background-color: #1682e6;
            }
            .el-slider__stop {
                background-color: #1682e6;
                border-radius: 0;
                width: 2px;
            }
            .el-slider__button-wrapper {
                pointer-events: auto;
            }
            .el-slider__marks-text {
                white-space: nowrap;
                color: #fff;
                font-size: 0;
            }
        }
        > span {
            flex-shrink: 0;
            transform: translateY(1px);
            color: #eee;
            cursor: pointer;
            margin: 0 5px;
            transition: 0.3s;
            font-size: 20px;
            &:hover {
                opacity: 0.5;
            }
        }
        > b {
            flex-shrink: 0;
            color: #eee;
            font-weight: normal;
            margin: 0 5px;
            cursor: pointer;
            border-radius: 3px;
            border: 1px solid #eee;
            padding: 0px 10px;
            transition: 0.3s;
            user-select: none;
            > span {
                vertical-align: middle;
                font-size: 14px;
                display: inline-block;
                transform: translateY(-2px);
            }
            i {
                vertical-align: middle;
                font-size: 16px;
                display: inline-block;
                transform: translateY(-1px);
            }
            &:hover {
                opacity: 0.5;
            }
        }
    }
  
}

六:完整代码

完整代码如下:

<!-- 
 * @description 轨迹回放
 * @fileName: track.vue 
 * @author: tan 
 * @date: 2024-06-17 10:02:28
!-->
<template>
    <div class="workTrack">
        <div id="myMap"></div>
        <div class="sliderBar" v-show="pathList.length">
            <span @click="cruiseStart()" v-if="!isPlay">
                <i class="el-icon-video-play"></i>
            </span>
            <span @click="cruisePause" v-else>
                <i class="el-icon-video-pause"></i>
            </span>
            <span @click="cruiseStop">
                <i class="el-icon-error"></i>
            </span>
            <el-slider :disabled="isPlay" v-model="sliderValue" :max="pointSum" :show-tooltip="false"></el-slider>
            <b @click="speedChange">
                <i class="el-icon-d-arrow-right"></i>
                <span>×{{ speedList[speedValue].value }}</span>
            </b>
        </div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            // 地图实例
            map: null,
            cruise: null, //巡航器实例
            cruiseIndex: -1, // 当前播放轨迹下标
            pathSimplifierIns: null, //轨迹实例
            isPlay: false, //是否播放
            isComplete: true, //是否完成
            pointSum: 0, //播放器总数
            sliderValue: 0, //播放器当前数
            startPoint: 0, //下次播放轨迹从当前值开始
            marksIndex: {}, //每段路的起止坐标
            // 轨迹坐标
            pathList: [
                // [经度,纬度] 可再次放置测试数据
                [120.79573938, 30.03576463],
            ],
            speedValue: 3, // 当前播放速度下标
            // 速度列表,可自定义配置
            speedList: [
                { value: 0.5, speed: 100 },
                { value: 1, speed: 200 },
                { value: 2, speed: 400 },
                { value: 4, speed: 1600 },
                { value: 8, speed: 12800 },
                { value: 16, speed: 25600 },
            ],
        };
    },
    mounted() {
        this.map = new AMap.Map('myMap', {
            zoom: 10, //级别
            center: [120.209758, 30.246809], //中心点坐标 默认在杭州
        });
        this.$nextTick(() => {
            this.loadMap();
        });
    },
    methods: {
        // 加载地图
        loadMap() {
            return new Promise((reslove, reject) => {
                //加载PathSimplifier,loadUI的路径参数为模块名中 'ui/' 之后的部分
                new AMapUI.load(['ui/misc/PathSimplifier'], PathSimplifier => {
                    if (!PathSimplifier.supportCanvas) {
                        alert('当前环境不支持 Canvas!');
                        return;
                    }
                    if (this.pathList?.length) {
                        //启动页面
                        this.initPage(PathSimplifier);
                    }
                });

                reslove();
            });
        },
        initPage(PathSimplifier) {
            let content = PathSimplifier.Render.Canvas.getImageContent(
                '/img/car1.png',
                () => {
                    //图片加载成功,重新绘制一次
                    this.pathSimplifierIns.renderLater();
                },
                function onerror(e) {
                    this.$message({ type: 'error', message: '图片加载失败!' });
                }
            );
            this.pathSimplifierIns = new PathSimplifier({
                zIndex: 100,
                map: this.map,
                getPath: function (pathData, pathIndex) {
                    return pathData.path;
                },

                renderOptions: {
                    //轨迹线的样式
                    getPathStyle: (pathItem, zoom) => {
                        return {
                            pathLineStyle: {
                                strokeStyle: 'red',
                                lineWidth: 6,
                                dirArrowStyle: true,
                            },
                        };
                    },
                    pathNavigatorStyle: {
                        initRotateDegree: 180,
                        width: 20,
                        height: 35,
                        autoRotate: true,
                        content,
                    },
                },
            });
            this.cruiseInit();
        },
        // 巡航器初始化
        cruiseInit() {
            let pathSimplifierIns = [{ path: this.pathList, color: '#28F' }];
            this.pathSimplifierIns.setData(pathSimplifierIns);
            this.pointSum = 0;
            let marksIndex = {};
            pathSimplifierIns.forEach((item, index) => {
                this.pointSum += item.path.length;
                marksIndex[index] = [0, this.pointSum];
            });

            this.marksIndex = marksIndex;
            this.cruiseStop();
        },
        // 创建一个巡航器
        createdCruise(index) {
            this.cruiseIndex++;
            // 判断是否传入index
            let cruiseIndex;
            if (index != undefined) {
                cruiseIndex = index;
                this.cruiseIndex = index;
            } else {
                cruiseIndex = this.cruiseIndex;
            }
            let cruise = this.pathSimplifierIns.createPathNavigator(
                cruiseIndex, //关联第index条轨迹
                {
                    loop: false, //循环播放
                    speed: this.speedList[this.speedValue].speed, //速度
                }
            );

            if (this.cruise) {
                // 清空走过的路线
                this.cruise.destroy();
                this.cruise = null;
            }

            return cruise;
        },
        // 开始播放
        cruiseStart() {
            this.isPlay = true;

            if (this.cruise && !this.cruise.isCursorAtPathEnd() && !this.cruise.isCursorAtPathStart() && !this.isComplete) {
                // 路段未开始并且没有结束的时候 暂停恢复动画 并且动画没有完成的时候
                this.cruise.resume();
                return;
            }
            this.isComplete = false;
            if (this.cruiseIndex == 0) {
                this.cruiseStop();
                return;
            }

            this.cruise = this.createdCruise();

            // 判断是否传入初始坐标
            if (this.startPoint) {
                this.cruise.start(this.startPoint);
                this.startPoint = 0;
            } else {
                this.cruise.start();
            }
            this.cruise.on('move', e => {
                let idx = this.cruise.cursor.idx;
                let { address, gpsTime, speed } = this.pathList[idx];
                let trackAddress = {
                    address,
                    gpsTime,
                    speed,
                };
                this.$emit('changeData', 'trackAddress', trackAddress);
                let [min, max] = this.marksIndex[this.cruiseIndex];
                this.sliderValue = idx + min;
            });
            // 巡航完成事触发
            this.cruise.on('pause', () => {
                if (this.cruise && this.cruise.isCursorAtPathEnd()) {
                    this.cruiseStart();
                }
            });
        },

        // 暂停播放
        cruisePause() {
            this.cruise.pause();
            this.isPlay = false;
        },
        // 停止
        cruiseStop() {
            if (this.cruise) {
                // 清空走过的路线
                this.cruise.destroy();
            }
            // 停止播放
            this.isPlay = false;
            this.isComplete = true;
            this.cruiseIndex = -1;
            // 为重新播放准备
            this.cruise = this.createdCruise();
            this.cruiseIndex = -1;
            this.sliderValue = 0;
        },

        speedChange() {
            if (this.speedValue == this.speedList.length - 1) {
                this.speedValue = 0;
            } else {
                this.speedValue++;
            }
            this.cruise.setSpeed(this.speedList[this.speedValue].speed);
        },
    },
    watch: {
        sliderValue(val) {
            // 正在播放禁止拖拽播放器
            if (!this.cruise || this.isPlay) return;
            this.cruise.moveToPoint(val);
            this.startPoint = val;
            this.pathSimplifierIns.render();
        },
    },

    beforeDestroy() {
        if (this.pathSimplifierIns) this.pathSimplifierIns.clearPathNavigators();
        if (this.pathSimplifierIns) this.pathSimplifierIns.setData([]);
        if (this.cruise) this.cruise.destroy();
        if (this.map) this.map.destroy();
    },
};
</script>

<style lang="scss" scoped>
.workTrack {
    width: 100%;
    position: relative;
    height: 100%;
    #myMap {
        width: 100%;
        height: 100%;
    }
    .sliderBar {
        position: absolute;
        bottom: 30px;
        user-select: none;
        width: 100%;
        padding: 10px 2%;
        background-color: #00000064;
        border-radius: 400px;
        backdrop-filter: blur(5px);
        z-index: 99;
        width: 80%;
        right: 0;
        left: 0;
        margin: auto;
        display: flex;
        justify-content: center;
        align-items: center;
        .el-slider {
            flex: 1;
            transform: translateY(1px);
            margin: 0 15px;
        }
        ::v-deep .el-slider__runway {
            pointer-events: none;
            background-color: #00000021;
            margin: 0;
            .el-slider__bar {
                background-color: #1682e6;
            }
            .el-slider__stop {
                background-color: #1682e6;
                border-radius: 0;
                width: 2px;
            }
            .el-slider__button-wrapper {
                pointer-events: auto;
            }
            .el-slider__marks-text {
                white-space: nowrap;
                color: #fff;
                font-size: 0;
            }
        }
        > span {
            flex-shrink: 0;
            transform: translateY(1px);
            color: #eee;
            cursor: pointer;
            margin: 0 5px;
            transition: 0.3s;
            font-size: 20px;
            &:hover {
                opacity: 0.5;
            }
        }
        > b {
            flex-shrink: 0;
            color: #eee;
            font-weight: normal;
            margin: 0 5px;
            cursor: pointer;
            border-radius: 3px;
            border: 1px solid #eee;
            padding: 0px 10px;
            transition: 0.3s;
            user-select: none;
            > span {
                vertical-align: middle;
                font-size: 14px;
                display: inline-block;
                transform: translateY(-2px);
            }
            i {
                vertical-align: middle;
                font-size: 16px;
                display: inline-block;
                transform: translateY(-1px);
            }
            &:hover {
                opacity: 0.5;
            }
        }
    }
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/735779.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

导入别人的net文件报红问题sdk

1. 使用cmd命令 dotnet --info 查看自己使用的SDK版本 2.直接找到项目中的 global.json 文件&#xff0c;右键打开&#xff0c;直接修改版本为本机的SDK版本&#xff0c;就可以用了

【STM32】STM32通过I2C实现温湿度采集与显示

目录 一、I2C总线通信协议 1.I2C通信特征 2.I2C总线协议 3.软件I2C和硬件I2C 二、stm32通过I2C实现温湿度&#xff08;AHT20&#xff09;采集 1.stm32cube配置 RCC配置&#xff1a; SYS配置&#xff1a; I2C1配置&#xff1a; USART1配置&#xff1a; GPIO配置&#…

智慧校园综合管理系统的优点有哪些

在当今这个信息化飞速发展的时代&#xff0c;智慧校园综合管理系统正逐步成为教育领域的一股革新力量&#xff0c;它悄然改变着我们对传统校园管理的认知。这套系统如同一个无形的桥梁&#xff0c;将先进的信息技术与学校的日常运作紧密相连&#xff0c;展现出多维度的优势。 …

网络技术原理需要解决的5个问题

解决世界上任意两台设备时如何通讯的&#xff1f;&#xff1f; 第一个问题&#xff0c;pc1和pc3是怎么通讯的&#xff1f; 这俩属于同一个网段&#xff0c;那么同网段的是怎么通讯的&#xff1f; pc1和pc2属于不同的网段&#xff0c;第二个问题&#xff0c;不同网段的设备是…

国企:2024年6月中国移动相关招聘信息 二

在线营销服务中心-中国移动通信有限公司在线营销服务中心 硬件工程师 工作地点:河南省-郑州市 发布时间 :2024-06-18 截至时间: 2024-06-30 学历要求:本科及以上 招聘人数:1人 工作经验:3年 岗位描述 1.负责公司拾音器等音视频智能硬件产品全过程管理,包括但…

【Java】Java基础语法

一、注释详解 1.1 注释的语法&#xff1a; // 单行注释/*多行注释 *//**文档注释 */ 1.2 注释的特点&#xff1a; 注释不影响程序的执行&#xff0c;在Javac命令进行编译后会将注释去掉 1.3 注释的快捷键 二、字面量详解 2.1 字面量的概念&#xff1a; 计算机是用来处理…

干货 | 2024生成式AI产业落地路径研究报告(免费下载)

【1】关注本公众号&#xff0c;转发当前文章到微信朋友圈 【2】私信发送 2024生成式AI产业落地路径研究报告 【3】获取本方案PDF下载链接&#xff0c;直接下载即可。 如需下载本方案PPT/WORD原格式&#xff0c;诚挚邀请您微信扫描以下二维码加入方案驿站知识星球&#xff0c;…

HMI 的 UI 风格,超凡脱俗

HMI 的 UI 风格&#xff0c;超凡脱俗

什么是孪生素数猜想

什么是孪生素数猜想 素数p与素数p2有无穷多对 孪生素数的公式&#xff08;详见百度百科&#xff1a;孪生素数公式&#xff09; 利用素数的判定法则&#xff0c;可以得到以下的结论&#xff1a;“若自然数q与q2都不能被任何不大于的素数 整除&#xff0c;则q与q 2都是素数”…

Redis预备知识

一.预备知识 1.基本全局命令 set key value 将key的值设置成value get key 得到key的值 keys [pattern] 查看匹配pattern的所有key 比如h?llo匹配hallo&#xff0c;hbllo&#xff0c;hcllo……只要用一个符号将&#xff1f;代替即可 比如h*llo匹配hllo&#xff0c;heeeello…

Java预约家政5.0服务本地服务源码(APP+小程序+公众号+H5)

预约家政本地服务平台系统&#xff1a;一站式解决家居需求&#x1f3e0;&#x1f4bc; 一、引言&#xff1a;开启便捷家居新时代 在快节奏的现代生活中&#xff0c;我们渴望拥有更多的时间和精力去享受生活&#xff0c;而不是被繁琐的家务所困扰。预约家政本地服务平台系统应…

远程医疗软件到底哪个好用?

随着科技进步的不断推进&#xff0c;远程医疗已经成为现代医疗体系的一个重要支柱。远程医疗软件&#xff0c;通过网络通信技术的运用&#xff0c;打破了地理限制&#xff0c;实现了医疗资源的有效整合与共享&#xff0c;为民众提供了前所未有的便捷高效的医疗服务体验。那么&a…

python tarfile解压失败怎么解决

问题原因 在使用tarfile模块解压一份Linux服务器上的打包文件时&#xff0c;出现了错误提示&#xff1a;IOError&#xff1a;[Errno 22] invalid mode (wb) or filename. 经过检查&#xff0c;发现是因为打包文件中有文件名存在“&#xff1a;”符号&#xff0c;而window下的…

上证所抓包实战

第 2 页jsonCallBack 回调函数Request Headers爬取股票列表下载时间戳Initiator在 Network 中抓到的包,有 Headers、Payload、Preview、Response、Initiator、Timing、Cookies 面板,从这些面板中获取有用的信息来写脚本。 上海证券交易所 https://www.sse.com.cn/assortment…

一款基于WordPress开发的高颜值的自适应主题Puock

主题特性 支持白天与暗黑模式 全局无刷新加载 支持博客与CMS布局 内置WP优化策略 一键全站变灰 网页压缩成一行 后台防恶意登录 内置出色的SEO功能 评论Ajax加载 文章点赞、打赏 支持Twemoji集成 支持QQ登录 丰富的广告位 丰富的小工具 自动百度链接提交 众多页面模板 支持评论…

OpenAI 的 GPT-5:CTO米拉-穆拉提说,到 2026 年将实现博士级智能(Ph.D.-Level))

据首席技术官米拉-穆拉提&#xff08;Mira Murati&#xff09;介绍&#xff0c;GPT-5 是 OpenAI 人工智能的下一代进化产品&#xff0c;将于 2025 年底或 2026 年初在特定任务中实现博士级智能。 GPT-5 内部代号为 "Gobi "和 “Arrakis”&#xff0c;将是一个多模态…

MyBatis映射器:一对多关联查询

大家好&#xff0c;我是王有志&#xff0c;一个分享硬核 Java 技术的金融摸鱼侠&#xff0c;欢迎大家加入 Java 人自己的交流群“共同富裕的 Java 人”。 在学习完上一篇文章《MyBatis映射器&#xff1a;一对一关联查询》后&#xff0c;相信你已经掌握了如何在 MyBatis 映射器…

论文《Tree Decomposed Graph Neural Network》笔记

【TDGNN】本文提出了一种树分解方法来解决不同层邻域之间的特征平滑问题&#xff0c;增加了网络层配置的灵活性。通过图扩散过程表征了多跳依赖性&#xff08;multi-hop dependency&#xff09;&#xff0c;构建了TDGNN模型&#xff0c;该模型可以灵活地结合大感受场的信息&…

接口性能优化方法总结

接口性能优化是后端开发人员经常碰到的一道面试题&#xff0c;因为它是一个跟开发语言无关的公共问题。 这个问题既可以很简单&#xff0c;也可以相当复杂。 导致接口性能问题的原因多种多样&#xff0c;不同项目的不同接口&#xff0c;其原因可能各不相同。 下面列举几种常…

Codeforces Round 953 (Div. 2) A~F

A.Alice and Books&#xff08;思维&#xff09; 题意&#xff1a; 爱丽丝有 n n n本书。第 1 1 1本书包含 a 1 a_1 a1​页&#xff0c;第 2 2 2本书包含 a 2 a_2 a2​页&#xff0c; … \ldots …第 n n n本书包含 a n a_n an​页。爱丽丝的操作如下&#xff1a; 她把所有的…