Day42:网易云项目,路由进阶
网易云项目
创建、启动项目并配置路由
npm init vite
npm i
npm i vue-router
npm i sass -D
在main.js中
import router from './router'
createApp(App).use(router).mount('#app')
在index中配置路由
import {createRouter,createWebHistory} from 'vue-router'
import Home from '../view/Home.vue'
import Search from '../view/Search.vue'
const router = createRouter ({history:createWebHistory(),routes:[{path:'/',name:'home',component:Home},{path:'/search',name:'search',component:Search}]
})
export default router
实现全局通用导航栏
写一个顶部的导航栏TopNav.vue在component文件夹中
<template><div class="top-nav"><div class="w content"><router-link to="/"><h1 class="logo"></h1></router-link><!-- 绑定一个导航,点击回到首页 --><div class="search-input"><input type="text" placeholder="请输入"v-model.trim="song"@keyup.enter="searchSong"/></div></div></div>
</template>
<script setup>import { ref } from "vue";import { useRouter } from "vue-router";const song = ref("")const router = useRouter()function searchSong(){router.push(`/search?song=${song.value}`)}
</script>
<style lang="scss" scoped>.top-nav {height: 70px;background-color: #242424;.content {display: flex;align-items: center;justify-content: space-between;h1 {width: 176px;height: 70px;background-image: url("https://s2.music.126.net/style/web2/img/frame/topbar.png?19dafe7dd55400ffec9b354833340e1f");background-position: 0 0;}.search-input {input {height: 40px;border-radius: 18px;padding: 5px 10px;outline: none;}}}}
</style>
useRoute和useRouter的区别,一个是获取全局路由,一个是获取当前页面的路由
在app中,将样式引入,并且去掉<style lang="scss" scoped>中的scoped,使导航栏能在全局应用
<template><div><top-nav/> <!-- 普通组件,不参与路由切换,是全局样式 --><router-view></router-view></div>
</template><script setup>
import TopNav from './components/TopNav.vue';
</script><style lang="scss">// scoped去掉,可以作为全局样式
* {padding: 0;margin: 0;box-sizing: border-box;
}
.w {width: 980px;margin: 0 auto;
}
</style>
获取axios请求的内容
在获取网易云数据的api中note app.js
在项目中
npm i axios
获取搜索的接口,放在search中,把连接板包裹在axios把获取的song.value拼接到链接后面,然后发axios请求
const route = useRoute()const song = ref("")const lists = ref([])song.value = route.query.songaxios.get(`http://localhost:3000/search?keywords=${song.value}`).then((res) => {lists.value = res.data.result.songs})
查询到数据得到一个30长度的array
将array中需要的数据渲染到页面
<template><div class="search"><div class="w list"><ul><li v-for="(item, index) in lists" :key="item.id" :class="{ active: index % 2 === 1 }"><p>{{ item.name }}</p><span><span class="inner_span" v-for="_item, _index in item.artists" :key="_index">{{ _item.name }}{{ _index + 1 < item.artists.length ? "/" : "" }}</span></span><span>{{ item.album.name }}</span><span>{{ format(item.duration) }}</span><!-- 格式化毫秒 --></li></ul></div></div>
</template>
得到的歌手不换行,超出的部分省略号,给innerspan添加三个样式即可
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
给每个歌手添加后斜杠,如果索引值+1小于数组长度就加斜杠,如果索引值+1不小于数组长度就不加斜杠{{_index + 1 < item.artists.length ? "/" : ""}}
给li添加斑马条纹样式和鼠标hover样式
<style lang="scss" scoped>.search {background-color: #eee;.list {background-color: #fff;border-left: 1px solid #615f5f;border-right: 1px solid #615f5f;ul {list-style: none;padding: 20px;li {display: flex;align-items: center;padding: 12px;gap: 10px;&.active {background-color: #f9f5f5;}&:hover {background-color: #e0dbdb;cursor: pointer;}p {width: 40%;}& > span {flex: 1;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;}}}}}
</style>
定义方法format用来毫秒值转分秒
分钟和秒如果不足10需要在前面添加字符串0。如果秒只有一位,获取秒数时只截取一位,然后添加字符串0;如果多于10,则截取前两位,后面多余的不要。
<script setup>import { useRoute } from "vue-router";import { ref } from "vue";import { format } from "path";import axios from "axios";function format(duration) {//毫秒转分秒let mins = Math.floor(duration / 1000 / 60)// 如果只有个位数要补一个0在前面if (mins < 10) {mins = "0" + mins}// 获取秒let secs = (duration / 1000) % 60// 字符串截取if (secs > 10) {secs = String(secs).slice(0, 2)} else {secs = "0" + String(secs)[0] // 只有一位前面加零,后面只截取一位}return mins + ':' + secs}const route = useRoute()const song = ref("")const lists = ref([])song.value = route.query.songaxios.get(`http://localhost:3000/search?keywords=${song.value}`).then((res) => {lists.value = res.data.result.songs})
</script>
在search页面重新搜索
需要监听song,如果song变化,需要重新发送请求,再把参数传给lists
封装axios请求为方法init(song)
在第一次加载的时候先运行一次init(song.value)
需要监听route.query.song的变化,变化了重新执行init
route.query是一个响应式对象,但route.query.song是一个响应式对象里的值,如果要对这个值进行监听,需要写一个函数包装他,并返回值,这样就不会出现报错了
封装了之后,axios请求中包裹的动态字符中的.value需要删除,因为监听已经直接针对song
const route = useRoute()
const song = ref("")
const lists = ref([])
song.value = route.query.song
function init(song) {axios.get(`http://localhost:3000/search?keywords=${song}`).then((res) => {lists.value = res.data.result.songs})
}
init(song.value) // 第一次加载的时候执行
watch(() => route.query.song,(newValue) => {song.value = newValueinit(song.value)})
登录页面项目
- 在login页面设置登录按钮,如果点击则传isLogin为true到本地存储,表示已经登录
<template><div>this is login<button @click="login">login</button></div>
</template>
<script setup>
function login() {//登录身份信息(token信息)只要登陆了,就在本地存,且设置为truelocalStorage.setItem('isLogin',true)// 在本地存储中找,如果有该字段且为true,则认为登录
}
</script>
- 在进入任何页面(除开login之外),要做一个身份认证,如果已经登录,可以进入这个页面,否则进入login身份认证
<template><div><router-view></router-view></div>
</template>
- 在生命周期钩子函数router.beforeEach进入到每个页面之前,都要进行钩子函数触发,被称为全局的前置路由导航守卫。
- 如果进入的页面不是login,或者没有登录(isLogin不是true),则强制回到login
-
- router.beforeEach((to,from) => {})参数to代表去哪个页面,from表示从哪里来
- 此代码写在路由页面router
router.beforeEach((to,from) => {// 如果进入了页面不是login,或者isLogin不是true,则强制回到loginif(to.name !== 'login' && !localStorage.getItem("isLogin")){return {name: "login"}}
})
单个路由导航守卫
router是全局路由,如果想精细化定制不同页面的跳转效果,可以在路由导航列表的对象里面书写路由导航守卫
localStorage.getItem("isLogin")需要用JSON包裹,否则可能会出现不能识别的情况
{path: '/detail',name: 'detail',component: Detail,// 单个路由对象的前置导航守卫beforeEnter (to, from) {if (to.name !== "/login" && !JSON.parse(localStorage.getItem("isLogin"))) {return {name: "login"}}}
},
前置导航守卫可以设置单个,但后置导航守卫可以设置全局的
前置导航守卫可以写在router的全局、局部,或者写在组件内部。推荐写在router
组件内部写法
setup语法糖无法触发beforeRouteEnter钩子函数,需要写完整格式
<script>
/* import { onBeforeEnter } from "vue-router";
onBeforeEnter() */
export default {beforeRouteEnter (to, from) {console.log('beforeenter')}
}
</script>
离开当前路由时触发导航守卫
<script>// 离开当前路由时,触发一个导航守卫beforeRouteLeave (to, from) {let res = window.confirm('您是否想离开本页面')if(!res) {return false // 如果是false,则留在本页面}}
}
</script>
路由进阶
1.路由导航守卫
顾名思义,路由导航守卫可以让每个页面完成跳转前后进行一些逻辑实现。vue-router提供了多种导航守卫:全局的,单个路由独享的,或者组件级的。现在来逐一说明。
路由导航守卫的详细说明
1.1 全局前置守卫
你可以使用 router.beforeEach 注册一个全局前置守卫,这样在匹配每个路由路径的时候都会进行一次进入前的"拦截",在某些需要验证登录状态的业务场景下应用极广。
我们仍然用示例来演示全局前置守卫的使用:
现在有3个页面,分别是登录页,首页,列表页。进入任何页面前都需要进行身份验证,必须本地存储中isLogin的字段为true时才可以进入,否则统一回到登录页。按照之前学习的内容快速完成路由信息的相关配置。
在配置完路由信息后,通过router.beforeEach 注册一个全局前置守卫,其中的守卫方法接受2个参数
- to:表示当前导航即将进入的页面
- from:表示当前导航即将离开的页面
前置守卫中通过返回的路由对象实现重定向。
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../components/Home.vue'
import Detail from '../components/Detail.vue'
import Login from '../components/Login.vue'const router = createRouter({history: createWebHistory(),routes: [{path: '/',name: 'home',components: Home,},{path: '/detail',name: 'detail',components: Detail,},{path: '/login',name: 'login',components: Login,},],
})
router.beforeEach((to, from) => {if (!localStorage.getItem('isLogin') && to.name !== 'login') {return {name: 'login',}}
})
export default router
在之前版本的路由中,还提供了第三个可选参数next,通过调用next方法也能进入到即将进入的路由页面,但新版本中不推荐这么做了。
1.2 全局后置守卫
和全局前置守卫类似,同样可以注册全局后置守卫,沿用上面的示例,在离开每个页面之前,都弹出一个提示框。
router.afterEach((to, from) => {alert('要离开此页面咯')
})
1.3 独享前置守卫
除了定义全局的路由守卫,还可以针对单个路由对象定义守卫:
{path: '/detail',name: 'detail',component: Detail,beforeEnter: (to, from) => {if (!localStorage.getItem('isLogin') && to.name !== 'login') {return {name: 'login',}}},
},
1.4 组件内部的路由守卫
除开在路由配置信息中定义导航守卫,还可以在组件内部定义守卫:
- beforeRouteEnter 进入路由前调用
- beforeRouteUpdate 动态参数改变时调用
- beforeRouteLeave 离开路由前调用
2.路由元信息
meta叫路由元信息,可以存储当前路由对象的一些信息
可以将任意信息添加到路由对象上,比如页面标题,鉴权认证等,Vue中的路由提供了一个meta字段,可以通过给每个路由对象配置meta字段来添加信息。
{path: '/',name: 'home',component: Home,meta: {title: '首页',},
},
在组件的生命周期中,可以将meta信息合理地调用出来。
//Home中 组件挂载完毕后 将页面的标题内容改为meta中存放的信息
<script setup>import { onMounted } from 'vue'import { useRoute } from 'vue-router'onMounted(() => {document.title = useRoute().meta.title})
</script>
这里需要写setup语法糖,但是组件内守卫不要写。虽然最好也不要写组件内守卫啦
<script setup>import { onMounted } from 'vue'import { useRoute } from 'vue-router'const route = useRoute() // 最好写在外面,不要写在钩子里onMounted(() => {document.title = route.meta.title})
</script>
3.路由嵌套
某些复杂的组件关系存在层级更深的路由,这是可以利用路由嵌套来实现,给需要添加二级路由的路由对象添加children属性来配置二级路由,同样使用来渲染出口。
现在给Detail路由页面添加二级子路由,能够显示用户详情和头像详情,在对应的路由配置中添加children属性
// 不要忘记最上面的引入!!!
{path: '/detail',name: 'detail',component: Detail,meta: {title: '详情页',},children: [{ path: 'users', name: 'users', component: Users },{ path: 'profile', name: 'profile', component: Profile },],},
建立好对应的路由组件后,需要在Detail中添加二级路由的出口:
<template><h1>这是详情页</h1><router-link to="users"> <button>用户详情页</button></router-link><router-link to="profile"> <button>头像详情页</button></router-link><router-view></router-view> // 记得渲染出口
</template>
嵌套路由的使用规则跟一级路由保持一致,当然如果你的业务足够复杂,还可以嵌套三级,四级路由。
4.路由滚动行为
切换路由的过程中,VueRouter还提供了操作滚动条行为的方法,通过scrollBehavior方法可以在路由配置中规定滚动条行为
const router = createRouter({history: createWebHashHistory(),routes: [...],scrollBehavior (to, from, savedPosition) {// return 期望滚动到哪个的位置return {top:30 //滚动到距离顶部30}}
})
5.路由懒加载
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效。
首页不用做懒加载,除开首页对所有的路由都使用动态导入。
Vue Router 支持开箱即用的动态导入,这意味着你可以用动态导入代替静态导入:
const Detail = () => import('../components/Detail.vue')const router = createRouter({// ...routes: [{ path: '/detail',name:'detail', component: Detail }],
})
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../view/Home.vue'
const router = createRouter({history: createWebHistory(),routes: [{path: '/login',name: 'login',component: ()=>import('../view/Login.vue'), // 改为懒加载meta: {title: '登录',},},
6.动态路由 (路由权限)
在登录页点击登录后,button新增了一个vip的button,可以进入vip页面。登录之后,才能在路由映射关系中加上vip对象(不能是控制按钮显示隐藏
对路由的添加通常是通过 配置routes来完成的,但是在某些情况下,你可能想在应用程序已经运行的时候添加或删除路由。例如在处理一些路由权限的场景下就需要动态增加路由。
6.1 增加路由
动态增加路由主要依靠router.addRoute()方法实现,获取到router实例后,可以在合理时机注册新的路由对象,
例如在登陆后新增一个Vip路由:
const login = () => {localStorage.setItem('isLogin', true)isVip.value = truerouter.addRoute({path: '/vip',name: 'vip',component: Vip,})
}
6.2 删除路由
动态删除路由最常用的方法是通过使用 router.removeRoute() 按名称删除路由,所以注册路由信息时添加name属性是一个好习惯,大家务必养成。
我们示例中登录退出希望将Vip路由删除掉:
const out = () => {localStorage.clear()isVip.value = falserouter.removeRoute('vip')
}
最终Login组件的页面代码会显得比较丰富完整:
<template><router-link to="/"><button>首页</button></router-link><router-link to="/detail"><button>详情页</button></router-link><router-link to="/vip" v-if="isVip"><button>Vip页</button></router-link><button @click="login">登录</button><button @click="out">退出登录</button>
</template><script setup>import { ref } from 'vue'import { useRouter } from 'vue-router'import Vip from '../components/Vip.vue'const router = useRouter()const login = () => {localStorage.setItem('isLogin', true)isVip.value = truerouter.addRoute({ // 登录成功后再添加路由映射关系path: '/vip',name: 'vip',component: Vip,})}const out = () => {localStorage.clear()// localStorage.removeItem('isLogin') //去掉登录身份信息isVip.value = falserouter.removeRoute('vip') // 退出登录后动态删除路由}let isVip = ref(localStorage.getItem('isLogin'))
</script><style></style>
6.3 查看当前路由
Vue Router 提供了两个功能来查看现有的路由:
- router.hasRoute():检查路由是否存在。
- router.getRoutes():获取一个包含所有路由记录的数组。
<template><div>this is login<button @click="login">login</button><button @click="logout">logout</button><button @click="$router.push('/')">首页</button><button @click="$router.push('/detail')">详情</button><router-link to="/vip" v-if="isVip"><button>Vip页</button></router-link></div>
</template>
<script setup>
import {onMounted,ref} from 'vue'
import { useRoute } from 'vue-router'
import { useRouter } from 'vue-router'
import Vip from './Vip.vue'
const router = useRouter()
// 使用json包裹,使isVip的状态依靠isLogin的状态改变
const isVip = ref(JSON.parse(localStorage.getItem("isLogin")))
function login() {//登录身份信息(token信息)只要登陆了,就在本地存,且设置为truelocalStorage.setItem('isLogin',true) // 在本地存储中找,如果有该字段且为true,则认为登录isVip.value = true// 登录之后,才在路由映射关系中加上vip对象router.addRoute({path: '/vip',name: 'vip',component: Vip,})
}
function logout() {//去掉登录身份信息localStorage.removeItem('isLogin')isVip.value = false// 动态删除路由router.removeRoute("vip")
}
const route = useRoute() // 最好写在外面,不要写在钩子里
onMounted(() => {document.title = route.meta.title
})
</script>
相关文章:

Day42:网易云项目,路由进阶
网易云项目 创建、启动项目并配置路由 npm init vite npm i npm i vue-router npm i sass -D 在main.js中 import router from ./router createApp(App).use(router).mount(#app) 在index中配置路由 import {createRouter,createWebHistory} from vue-router import H…...

Open3D(C++) 三维点云边界提取
目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 见:PCL 点云边界提取 二、代码实现 BoundaryEstimation.h #pragma...
AUTOSAR汽车电子嵌入式编程精讲300篇-经典 AUTOSAR 安全防御能力的分析及改善
目录 前言 研究现状 经典 AUTOSAR 概述 2.1 经典 AUTOSAR 架构 2.2 经典 AUTOSAR 应用层...

LeetCode 1584. 连接所有点的最小费用【最小生成树】
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…...

超简单,几行js代码就实现一个 vue3 的数字滚动效果!
预览效果 1. 创建一个template <template><div class"num-warp"><template v-for"item in numStr"><div v-if"item ," class"dot">,</div><divv-elseclass"num-box":style"{transf…...

两阶段鲁棒优化matlab实现——CCG和benders
目录 1 主要内容 2 部分代码 3 程序结果 4 程序链接 1 主要内容 程序采用matlab复现经典论文《Solving two-stage robust optimization problems using a column-and-constraint generation method》算例,实现了C&CG和benders算法两部分内容,通过…...

二进制安全虚拟机Protostar靶场(4)写入shellcode,基础知识讲解 Stack Five
前言 这是一个系列文章,之前已经介绍过一些二进制安全的基础知识,这里就不过多重复提及,不熟悉的同学可以去看看我之前写的文章 二进制安全虚拟机Protostar靶场 安装,基础知识讲解,破解STACK ZERO https://blog.csdn.net/qq_45894840/artic…...

【Flink实战】玩转Flink里面核心的Source Operator实战
🚀 作者 :“大数据小禅” 🚀 文章简介 :【Flink实战】玩转Flink里面核心的Source Operator实战 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 目录导航 Flink 的API层级介绍Source Operator速览Flin…...
[2023-09-12]Oracle备库查询报ORA-01187
一个多表关联的语句在备库执行查询时提示ORA-01187: cannot read from file because it failed verification tests,单独对某一个表查询则正常返回(因为不需要排序等,没有用到临时表空间)。 查看报错信息发现是提示的临时数据文件…...
leetcode 16.最接近的三数之和
给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。 返回这三个数的和。 假定每组输入只存在恰好一个解。 示例 1: 输入:nums [-1,2,1,-4], target 1 输出:…...
antd table 自定义排序图标
要在Ant Design的Table组件中自定义排序图标,可以使用sorter和sortDirections属性来实现自定义排序逻辑和图标。以下是一个示例,演示如何在Ant Design的Table中自定义排序图标: import React, { useState } from react; import { Table, Spa…...

第十九章、【Linux】开机流程、模块管理与Loader
19.1.1 开机流程一览 以个人计算机架设的 Linux 主机为例,当你按下电源按键后计算机硬件会主动的读取 BIOS 或 UEFI BIOS 来载入硬件信息及进行硬件系统的自我测试, 之后系统会主动的去读取第一个可开机的设备 (由 BIOS 设置的) …...

GMAC PHY介绍
1.1PHY接口发展 (1)MII支持10M/100Mbps,一个接口由14根线组成,它的支持还是比较灵活的,但是有一个缺点是因为它一个端口用的信号线太多。参考芯片:DP83848 、DM900A(该芯片内部集成了MAC和PHY接…...
华为OD机考算法题:最远足迹
目录 题目部分 解读与分析 代码实现 题目部分 题目最远足迹难度易题目说明某探险队负责对地下洞穴进行探险。 探险队成员在进行探险任务时,随身携带的记录器会不定期地记录自身的坐标,但在记录的间隙中也会记录其他数据。探索工作结束后,…...

QScrollBar滚动条、QSlider滑块、 QDial表盘
QAbstractSlider 类、 QSCrollBar 类、 QSlider 类 一、 基本原理 1、 QAbstractSlider 继承自 QWidget,该类主要用于提供一个范围内的整数值, 2、 QAbstractSlider 类是 QScrollBar 类(滚动条)、 QSlider 类(滑块)、 QDial 类(表盘)的父类,因…...

Prometheus+Grafana可视化监控【MySQL状态】
文章目录 一、安装Docker二、安装MySQL数据库(Docker容器方式)三、安装Prometheus四、安装Grafana五、Pronetheus和Grafana相关联六、安装mysqld_exporter七、Grafana添加MySQL监控模板 一、安装Docker 注意:我这里使用之前写好脚本进行安装Docker,如果…...
五,编译定制rom并刷机实现硬改(二)
系列文章目录 第一章 安卓aosp源码编译环境搭建 第二章 手机硬件参数介绍和校验算法 第三章 修改安卓aosp代码更改硬件参数 第四章 编译定制rom并刷机实现硬改(一) 第五章 编译定制rom并刷机实现硬改(二) 第六章 不root不magisk不xposed lsposed frida原生修改定位 第七章 安卓…...

Modbus协议详解3:数据帧格式 - RTU帧 ASCII帧的区别
Modbus既然是一种通信协议,那它就应该有规定的通信格式用于在设备之间的指令接收与识别。 本文就着重讲讲Modbus协议的RTU帧和ASCII帧。 Modbus帧在串行链路上的格式如下: 在上图的格式中: 1)地址域:指代的是子节点地址…...

认识数据分析
文章目录 1. 认识数据分析1.1 数据自身的三大属性1.2 建数仓 数据分析的工程技术1.3 数据分析解决问题的原理1.4 数据分析的具体流程1.5 数据的中心化和智能化1.6 数据分析的四种类型和六个方向 1. 认识数据分析 1.1 数据自身的三大属性 客观:用数字衡量和表现一件…...
Learn Prompt-ChatGPT 精选案例:写作博客
在 ChatGPT 的帮助下,文本内容的产出,尤其是撰写博客文章的过程得到了进一步的简化。你可以让 ChatGPT 激发你的灵感,也可以让它美化你的文章内容。 这里我们希望能通过prompt写出一篇以“ChatGPT对社会各行各业的影响”为主题的博客。 本页…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...