当前位置: 首页 > news >正文

【组件封装】uniapp vue3 封装一个完整的Tabs(标签页)组件教程,功能由简到杂实现讲解。

文章目录

  • 前言
  • 一、简单版Tabs
    • 代码实现:
  • 二、下划线带动画的Tabs
    • API回顾:
    • 代码实现:
  • 三、内容区域滑动切换+切换动画
    • 代码实现:
    • (2)禁用手势滑动切换
    • (3)内容区域换为插槽
  • 四、标签栏可滚动
    • 代码实现


前言

手把手教你封装一个移动端 Tabs组件(标签页),功能由简到杂以uniapp vue3为代码示例。


请添加图片描述

一、简单版Tabs

实现一个最简单版的Tabs,下划线无动画无手势切换等,如下图所示:

请添加图片描述

实现说明:标签通过flex布局排列,下划线通过伪类绝对定位在选中项底部,选中项通过索引记录动态添加激活class

代码实现:

tabs.vue

<template><view class="tabs"><view :class="['tab',{active:index==selectIndex}]" v-for="(item,index) in  list" :key="index"@click="handleSelect(index)">{{item}}</view></view>
</template><script setup>import {computed,ref} from 'vue'const props = defineProps({//标签配置list: {type: Array,default: () => []},//激活颜色activeColor: {type: String,defalut: 'deepskyblue'}})//激活颜色const activeColor = computed(() => {return props.activeColor || 'deepskyblue'})//当前选中索引const selectIndex = ref(0)//切换标签const handleSelect = (index) => {if (index !== selectIndex.value) {selectIndex.value = index}}
</script><style lang="scss" scoped>.tabs {width: 100%;display: flex;align-items: center;background-color: #fff;.tab {flex: 1;padding: 25rpx 10rpx;width: 0;box-sizing: border-box;text-align: center;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;color: #333;font-size: 30rpx;position: relative;&.active {font-weight: bold;color: v-bind(activeColor);//下划线&::after {display: block;content: '';position: absolute;bottom: 0;left: 50%;transform: translateX(-50%);width: 30px;height: 6rpx;background-color: v-bind(activeColor);border-radius: 6rpx;}}}}
</style>

ps:注意scss中使用了v-bind引用vue变量activeColor动态设置标签和下划线激活颜色


二、下划线带动画的Tabs

接下来功能升级,要求切换标签的时候下划线有滑动动画,如下图所示

请添加图片描述

实现说明:因为下划线要有滑动动画,就不能相对于选中项绝对定位,而应该基于一个固定的父级元素定位,这个父元素就是组件最外层容器。选中后通过计算下划线到父容器距离(也就是下划线到页面最左边距离)确定绝对定位的left值,同时设置过渡动画。

API回顾:

在uniapp中由于底层使用引擎不同小程序或者app中无法像h5一样进行任何dom操作,只能通过官方提供的api来获取节点信息。

uni.createSelectorQuery()可用于获取节点信息,并结合如下使用方式:

import { getCurrentInstance } from 'vue';
const instance = getCurrentInstance();const query = uni.createSelectorQuery().in(instance.proxy);
query.select("#id").boundingClientRect((data) => {console.log("得到布局位置信息" + JSON.stringify(data));console.log("节点离页面顶部的距离为" + data.top);console.log("节点离页面左边的距离为" + data.left);}).exec();

来获取节点宽高和距离窗口左边或者顶部距离。

下划线位置计算:
在这里插入图片描述
下划线绝对定位left值=a段长度,a=b+标签宽/2,而b为标签与页面左边距离,b和标签宽都可以通过节点信息api获取
ps:因为下划线设置了css属性值 transform: translateX(-50%),向左平移自身一半,所以left值为a

代码实现:

tabs.vue

<template><view class="tabs"><!-- 标签栏 --><view :class="['tab',{active:index==selectIndex}]" v-for="(item,index) in  list" :key="index"@click="handleSelect(index)">{{item}}</view><!-- 下划线 --><view :class="['underline',{transition:left!==null}]"></view></view>
</template><script setup>import {computed,ref,onMounted,nextTick,getCurrentInstance} from 'vue'const props = defineProps({//标签配置list: {type: Array,default: () => []},//激活颜色activeColor: {type: String,defalut: 'deepskyblue'}})//激活颜色const activeColor = computed(() => {return props.activeColor || 'deepskyblue'})//当前选中索引const selectIndex = ref(0)//切换标签const handleSelect = (index) => {if (index !== selectIndex.value) {selectIndex.value = indexsetPosition()}}//下划线离父元素左边距const left = ref(null)//组件实例const instance=getCurrentInstance()//设置下划线位置const setPosition = () => {nextTick(() => {let query = uni.createSelectorQuery().in(instance.proxy)query.select(".active").boundingClientRect(data => {//定位距离=选中标签项与左距离+标签宽一半left.value =`${data.left+data.width/2}px`}).exec()})}onMounted(() => {//设置下划线初始位置setPosition()})
</script><style lang="scss" scoped>.tabs {width: 100%;display: flex;align-items: center;background-color: #fff;position: relative;.tab {flex: 1;padding: 25rpx 10rpx;width: 0;box-sizing: border-box;text-align: center;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;color: #333;font-size: 30rpx;position: relative;&.active {font-weight: bold;color: v-bind(activeColor);}}}//下划线.underline {position: absolute;width: 30px;height: 6rpx;background-color: v-bind(activeColor);border-radius: 6rpx;bottom: 0;left: v-bind(left);transform: translateX(-50%);display: none;&.transition {display: block;transition: all 0.3s;}}
</style>

ps:下划线绝对定位left值在scss通过 v-bind动态访问vue变量


三、内容区域滑动切换+切换动画

在上述示例基础上继续扩展功能,目标是切换标签页支持内容区域带动画同时内容区域滑动可以切换标签,如下图所示:

请添加图片描述

实现说明:结合swiper轮播图组件封装,内容区域使用swiper作为父容器,因为swiper支持手势滑动和滑动动画。

代码实现:

tabs.vue

<template><view class="comp-container"><view class="tabs"><!-- 标签栏 --><view :class="['tab',{active:index==selectIndex}]" v-for="(item,index) in  list" :key="index"@click="handleSelect(index)">{{item}}</view><!-- 下划线 --><view :class="['underline',{transition:left!==null}]"></view></view><!-- 内容区域 --><view class="content"><swiper class="swiper" :current="selectIndex" @change="onSwiperChange"><swiper-item class="swiper-item" v-for="item in list" :key="item"><scroll-view scroll-y style="height:100%"><!-- 页面内容 --><view class="main">{{item}}</view></scroll-view></swiper-item></swiper></view></view>
</template><script setup>import {computed,ref,onMounted,nextTick,getCurrentInstance} from 'vue'const props = defineProps({//标签配置list: {type: Array,default: () => []},//激活颜色activeColor: {type: String,defalut: 'deepskyblue'}})//激活颜色const activeColor = computed(() => {return props.activeColor || 'deepskyblue'})//当前选中索引const selectIndex = ref(0)//切换标签const handleSelect = (index) => {if (index !== selectIndex.value) {selectIndex.value = indexsetPosition()}}//下划线离父元素左边距const left = ref(null)//组件实例const instance = getCurrentInstance()//设置下划线位置const setPosition = () => {nextTick(() => {let query = uni.createSelectorQuery().in(instance.proxy)query.select(".active").boundingClientRect(data => {//定位距离=选中标签项与左距离+标签宽一半left.value = `${data.left+data.width/2}px`}).exec()})}onMounted(() => {//设置下划线初始位置setPosition()})//手势切换回调const onSwiperChange = e => {if (e.detail.current !== selectIndex.value) {handleSelect(e.detail.current)}}
</script><style lang="scss" scoped>.comp-container {height: 100%;display: flex;flex-direction: column;background-color: #f2f2f2;overflow: hidden;}.tabs {width: 100%;display: flex;align-items: center;background-color: #fff;position: relative;flex-shrink: 0;.tab {flex: 1;padding: 25rpx 10rpx;width: 0;box-sizing: border-box;text-align: center;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;color: #333;font-size: 30rpx;position: relative;&.active {font-weight: bold;color: v-bind(activeColor);}}}//下划线.underline {position: absolute;width: 30px;height: 6rpx;background-color: v-bind(activeColor);border-radius: 6rpx;bottom: 0;left: v-bind(left);transform: translateX(-50%);display: none;&.transition {display: block;transition: all 0.3s;}}.content {flex: 1;height: 0;overflow: hidden;.swiper {height: 100%;.swiper-item {height: 100%;}}.main {background: #f2f2f2;text-align: center;padding: 30rpx;box-sizing: border-box;}}
</style>

页面引用:
index.vue

<template><view class="container"><Tabs :list="list" /></view>
</template><script setup>import Tabs from '@/components/tabs.vue'import {ref} from 'vue'const list = ref(['手机', '电脑', '电视机', '洗衣机'])
</script><style lang="scss" scoped>.container {height: 100vh;background-color: #f2f2f2;}
</style>

说明:为了使内容区域可滚动,内嵌了scroll-view,而scroll-view需要指定高度,整个组件高度默认继承父元素100%,所以在页面使用tabs组件时父元素必须设置高度。

(2)禁用手势滑动切换

swiper组件有个属性disable-touch用来禁用轮播图触摸操作,该属性只支持App 2.5.5+、H5 2.5.5+、支付宝小程序、抖音小程序与飞书小程序。微信小程序可以通过@touchmove.prevent阻止触摸事件冒泡来阻止页面滑动

代码实现:

<template><view class="comp-container"><view class="tabs"><!-- 标签栏 --><view :class="['tab',{active:index==selectIndex}]" v-for="(item,index) in  list" :key="index"@click="handleSelect(index)">{{item}}</view><!-- 下划线 --><view :class="['underline',{transition:left!==null}]"></view></view><!-- 内容区域 --><view class="content"><swiper class="swiper" :current="selectIndex" disable-touch @change="onSwiperChange"><swiper-item class="swiper-item" v-for="item in list" :key="item" @touchmove.prevent><scroll-view scroll-y style="height:100%"><!-- 页面内容 --><view class="main">{{item}}</view></scroll-view></swiper-item></swiper></view></view>
</template>

运行效果:
请添加图片描述

(3)内容区域换为插槽

内容区域通过动态插槽提供给页面自定义渲染

核心代码如下:

	<!-- 内容区域 --><view class="content"><swiper class="swiper" :current="selectIndex" @change="onSwiperChange"><swiper-item class="swiper-item" v-for="(item,index) in list" :key="index"><scroll-view scroll-y style="height:100%"><!-- 页面内容 --><!-- #ifdef H5 ||APP --><slot :name="`content${index}`"></slot><!--#endif --><!-- #ifdef MP-WEIXIN --><slot name="content{{index}}"></slot><!--#endif --></scroll-view></swiper-item></swiper></view>

需要注意的是微信小程序端不支持vue插槽动态命名语法,需要写成双花括号形式。

完整代码:
tabs.vue

<template><view class="comp-container"><view class="tabs"><!-- 标签栏 --><view :class="['tab',{active:index==selectIndex}]" v-for="(item,index) in  list" :key="index"@click="handleSelect(index)">{{item}}</view><!-- 下划线 --><view :class="['underline',{transition:left!==null}]"></view></view><!-- 内容区域 --><view class="content"><swiper class="swiper" :current="selectIndex" @change="onSwiperChange"><swiper-item class="swiper-item" v-for="(item,index) in list" :key="index"><scroll-view scroll-y style="height:100%"><!-- 页面内容 --><!-- #ifdef H5 ||APP --><slot :name="`content${index}`"></slot><!--#endif --><!-- #ifdef MP-WEIXIN --><slot name="content{{index}}"></slot><!--#endif --></scroll-view></swiper-item></swiper></view></view>
</template><script setup>import {computed,ref,onMounted,nextTick,getCurrentInstance} from 'vue'const props = defineProps({//标签配置list: {type: Array,default: () => []},//激活颜色activeColor: {type: String,defalut: 'deepskyblue'}})//激活颜色const activeColor = computed(() => {return props.activeColor || 'deepskyblue'})//当前选中索引const selectIndex = ref(0)//切换标签const handleSelect = (index) => {if (index !== selectIndex.value) {selectIndex.value = indexsetPosition()}}//下划线离父元素左边距const left = ref(null)//组件实例const instance = getCurrentInstance()//设置下划线位置const setPosition = () => {nextTick(() => {let query = uni.createSelectorQuery().in(instance.proxy)query.select(".active").boundingClientRect(data => {//定位距离=选中标签项与左距离+标签宽一半left.value = `${data.left+data.width/2}px`}).exec()})}onMounted(() => {//设置下划线初始位置setPosition()})//手势切换回调const onSwiperChange = e => {if (e.detail.current !== selectIndex.value) {handleSelect(e.detail.current)}}
</script><style lang="scss" scoped>.comp-container {height: 100%;display: flex;flex-direction: column;background-color: #f2f2f2;overflow: hidden;}.tabs {width: 100%;display: flex;align-items: center;background-color: #fff;position: relative;flex-shrink: 0;.tab {flex: 1;padding: 25rpx 10rpx;width: 0;box-sizing: border-box;text-align: center;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;color: #333;font-size: 30rpx;position: relative;&.active {font-weight: bold;color: v-bind(activeColor);}}}//下划线.underline {position: absolute;width: 30px;height: 6rpx;background-color: v-bind(activeColor);border-radius: 6rpx;bottom: 0;left: v-bind(left);transform: translateX(-50%);display: none;&.transition {display: block;transition: all 0.3s;}}.content {flex: 1;height: 0;overflow: hidden;.swiper {height: 100%;.swiper-item {height: 100%;}}.main {background: #f2f2f2;text-align: center;padding: 30rpx;box-sizing: border-box;}}
</style>

页面调用:
index.vue

<template><view class="container"><Tabs :list="list" ><template #content0>手机</template><template #content1>电脑</template><template #content2>电视机</template><template #content3>洗衣机</template></Tabs></view>
</template><script setup>import Tabs from '@/components/tabs.vue'import {ref} from 'vue'const list = ref(['手机', '电脑', '电视机', '洗衣机'])
</script><style lang="scss" scoped>.container {height: 100vh;background-color: #f2f2f2;}
</style>

四、标签栏可滚动

最终版——功能继续升级,上述案例都是基于标签比较少的场景下使用,如果标签很多超出屏幕就不再适用,此时标签栏需要支持滚动。
我们目标不仅支持滚动,更友好操作体验还希望实现点击某个标签自动移动到屏幕中间,如下图所示:

请添加图片描述

实现说明:

1、横向滚动:
布局上标签栏外层使用scroll-view包裹,内层依然使用flex布局,每个标签设置基础宽度,当标签过多总体宽度超出屏幕就出现横向滚动。

2、选中标签移动到屏幕中间:
需要分别计算滚动条位置和下划线位置

(1)滚动条位置
scroll-view 有个scroll-left属性控制滚动条位置,我们只需计算该值即可。
在这里插入图片描述

如上图所示,假设点击了热水器标签,热水器标签要移动到屏幕中间,需要平移a段距离,a=c+b/2,其中b为标签自身宽度,c为标签距离页面左边距离-页面宽/2,最终滚动条scrollLeft值=原scrollLeft值+a,所以每次标签切换都要记录计算scrollLeft值,scrollLeft初始值为
0。上述几个值都可以通过节点信息api获取。
需要注意的是如果点击第一或第二个标签或最后一个标签情况是无法使得标签移动到正中间,因为滚动条长度有限,所以在计算scrollLeft值时候需要限制最大值最小值。最小值为0,最大值为滚动条长度-页面宽度,而滚动条长度可以通过如下api获取:

query.select('#scrollview').fields({size: true,scrollOffset: true},(data) => {console.log(data.scrollWidth,'滚动条长度')})

(2)下划线位置
下划线还是和之前的案例一样基于父容器绝对定位,因为滚动条的出现使得父容器不在位于页面最左边,而是滚动条最左边,所以下划线位置还需加上滚动条滚出左边页面区域长度也即scrollLeft值

代码实现

tabs.vue

<template><view class="comp-container"><view class="tabs"><!-- 标签栏 --><scroll-view id="scrollview" :scroll-left="scrollLeft" scroll-x style="width:100%" scroll-with-animation><view class="title-wrap" ><view :class="[selectedIndex===index ?'active':'','title-item']" v-for="(item,index) in list":key="item" @click="onSelect(index)">{{item}}</view><!-- 下划线 --><view :class="['underline',{transition:left!==null}]"></view></view></scroll-view></view><!-- 内容区域 --><view class="content"><swiper class="swiper" :current="selectedIndex" @change="onSwiperChange" ><swiper-item class="swiper-item" v-for="(item,index) in list" :key="index"><scroll-view scroll-y style="height:100%"><!-- 页面内容 --><!-- #ifdef H5 ||APP --><slot :name="`content${index}`"></slot><!--#endif --><!-- #ifdef MP-WEIXIN --><slot name="content{{index}}"></slot><!--#endif --></scroll-view></swiper-item></swiper></view></view>
</template><script setup>import {ref,onMounted,getCurrentInstance,nextTick,computed} from 'vue'const props = defineProps({//标签配置list: {type: Array,default: () => []},//激活颜色activeColor: {type: String,defalut: 'deepskyblue'}})//当前选中索引const selectedIndex = ref(0)//下划线离父元素左边距const left = ref(null)const instance = getCurrentInstance()//窗口宽度const winWidth = uni.getSystemInfoSync().windowWidth//设置滚动条和下划线位置const setPosition = () => {nextTick(() => {let query = uni.createSelectorQuery().in(instance.proxy)query.select(".active").boundingClientRect(async data => {//获取滚动条节点信息let scrollViewInfo= await getScrollViewInfo();//重新获取滚动条scrollLeft值,防止用户手动触发滚动情况下值scrollLeft未及时更新scrollLeft.value=scrollViewInfo.scrollLeftlet offsetLeft = data.leftlet offsetWidth = data.width//设置下划线位置left.value = ((offsetLeft + offsetWidth / 2) + scrollLeft.value) + 'px'//计算滚动条位置let _scrollLeft=scrollLeft.value+ data.left + offsetWidth / 2 - winWidth / 2//限制滚动范围_scrollLeft = Math.max(0, _scrollLeft)//设置滚动条位置scrollLeft.value = Math.min(_scrollLeft, scrollWidth.value - winWidth)}).exec()})}//选中标签监听事件const onSelect = index => {if (index !== selectedIndex.value) {selectedIndex.value = index;setPosition()}}//手势切换回调const onSwiperChange = e => {if (e.detail.current !== selectedIndex.value) {onSelect(e.detail.current)}}//滚动条位置const scrollLeft = ref(0)//滚动条长度const scrollWidth = ref(0)//获取滚动条长度和位置信息const getScrollViewInfo = () => {return new Promise((resolve, reject) => {let query = uni.createSelectorQuery().in(instance.proxy)query.select('#scrollview').fields({size: true,scrollOffset: true,},(data) => {resolve({scrollWidth:data.scrollWidth,scrollLeft:data.scrollLeft})}).exec()})}onMounted(() => {nextTick(async () => {//初始化化记录滚动条长度let res= await getScrollViewInfo();scrollWidth.value=res.scrollWidthsetPosition()})})
</script><style lang="scss" scoped>:deep(::-webkit-scrollbar) {display: none;}.comp-container {height: 100%;display: flex;flex-direction: column;background-color: #f2f2f2;overflow: hidden;}.tabs {width: 100%;position: relative;flex-shrink: 0;background-color: #fff;.title-wrap {width: 100%;display: flex;align-items: center;box-sizing: border-box;justify-content: flex-start;position: relative;.title-item {padding: 25rpx 10rpx;flex: 1 0 22%;width: 0;box-sizing: border-box;text-align: center;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;&.active {color: deepskyblue;font-weight: bold;}}}.underline {position: absolute;width: 30px;height: 6rpx;background-color: deepskyblue;border-radius: 6rpx;bottom: 0;left: v-bind(left);transform: translateX(-50%);display: none;&.transition {display: block;transition: all 0.3s;}}}.content {flex: 1;height: 0;overflow: hidden;.swiper {height: 100%;.swiper-item {height: 100%;}}.main {background: #f2f2f2;padding: 30rpx;text-align: center;}}
</style>

页面调用
index.vue

<template><view class="container"><Tabs :list="list"><template #content0>手机</template><template #content1>电脑</template><template #content2>电视机</template><template #content3>洗衣机</template><template #content4>洗碗机</template><template #content5>热水器</template><template #content6>电冰箱</template><template #content7>烤箱</template></Tabs></view>
</template><script setup>import Tabs from '@/components/tabs.vue'import {ref} from 'vue'const list = ref(['手机', '电脑', '电视机', '洗衣机', '洗碗机', '热水器', '电冰箱', '烤箱'])
</script><style lang="scss" scoped>.container {height: 100vh;background-color: #f2f2f2;}
</style>

相关文章:

【组件封装】uniapp vue3 封装一个完整的Tabs(标签页)组件教程,功能由简到杂实现讲解。

文章目录 前言一、简单版Tabs代码实现&#xff1a; 二、下划线带动画的TabsAPI回顾&#xff1a;代码实现&#xff1a; 三、内容区域滑动切换切换动画代码实现&#xff1a;&#xff08;2&#xff09;禁用手势滑动切换&#xff08;3&#xff09;内容区域换为插槽 四、标签栏可滚动…...

AI在SEO中的应用与关键词优化探讨

内容概要 在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;技术为搜索引擎优化&#xff08;SEO&#xff09;带来了革命性的改变。传统的SEO主要依赖于人为的经验和判断&#xff0c;而AI则通过算法分析海量数据&#xff0c;提供更加精准和高效的方式优化关键词…...

JUC:Synchronized和锁升级

1. 面试题 谈谈你对Synchronized的理解Sychronized的锁升级你聊聊Synchronized实现原理&#xff0c;monitor对象什么时候生成的&#xff1f;知道monitor的monitorenter和monitorexit这两个是怎么保证同步的嘛&#xff1f;或者说这两个操作计算机底层是如何执行的偏向锁和轻量级…...

如何使用锁实现多进程和多线程的并发执行的安全

多进程和多线程的并发&#xff1a; 多进程和多线程的并发意思是在同一段时间内&#xff0c;多个进程或者线程一起执行&#xff0c;但是这些进程或者线程的执行并不是真正意义上在同一时刻执行&#xff0c;而是在不同的时间里执行&#xff0c;因为每个CPU在同一时间只能处理同一…...

LabVIEW如何用运动控制卡实现伺服电机的转矩控制?

在LabVIEW中&#xff0c;使用运动控制卡实现伺服电机的转矩控制&#xff0c;通常通过以下几个步骤来完成。这里将结合LabVIEW的运动控制功能和伺服电机控制的基本原理进行详细介绍。 ​ 1. 选择合适的运动控制卡 要实现伺服电机的转矩控制&#xff0c;首先需要一张支持伺服电…...

SQL面试题——百度SQL面试题 无效搜索

百度SQL面试题 无效搜索 今天的题目是来自百度的SQL 面试题目 现有一份用户搜索日志,包含用户ID,时间,用户搜索内容。定义 无效搜索:如果用户下一次搜索内容中包含本次搜索内容,则认为本次搜索为无效搜索。请查询用户无效搜索记录 +---------+---------------------+--…...

媒体查询、浏览器一帧渲染过程

文章目录 媒体查询语法示例根据视口宽度应用不同的样式根据设备像素比应用不同的样式根据方向应用不同的样式 使用场景 浏览器一帧的渲染过程 媒体查询 媒体查询&#xff08;Media Query&#xff09;是CSS3中的一个重要特性&#xff0c;它允许开发者根据设备的特定条件&#x…...

实习工作日志

工作日志 遇到的bug 由于不熟悉Python&#xff0c;造成了这个bug python的浅拷贝与深拷贝&#xff0c;一定要创建新的变量&#xff0c;否则只是单纯拷贝地址...

JavaWeb学习--cookie和session

目录 &#xff08;一&#xff09;Cookie概述 1.什么叫Cookie 2.Cookie规范 3.Cookie的覆盖 4.cookie的最大存活时间 ​​​​​​&#xff08;Cookie的生命&#xff09; &#xff08;二&#xff09; Cookie的API 1.创建Cookie&#xff1a;new 构造方法 2.保存到客户端浏…...

ETCD的封装和测试

etcd是存储键值数据的服务器 客户端通过长连接watch实时更新数据 场景&#xff1a; 当主机A给服务器存储 name&#xff1a; 小王 主机B从服务器中查name ,得到name-小王 当主机A更改name 小李 服务器实时通知主机B name 已经被更改成小李了。 应用&#xff1a;服务注册与发…...

c++引用笔记

1 引用的基本使用 // 引用 // 作用&#xff1a;给变量起别名 // 语法&#xff1a;数据类型 &别名 原名int main(int argc, char const *argv[]) {int a 10;int &b a;cout << "a " << a << endl;cout << "b " <&l…...

macOS运行amd64的镜像

在macOS上运行amd64&#xff08;x86_64&#xff09;架构的镜像&#xff0c;通常通过虚拟化或仿真工具来实现。例如&#xff0c;如果你使用的是基于Apple Silicon&#xff08;M1或M2等&#xff09;芯片的Mac&#xff0c;那么你的处理器是ARM架构的&#xff0c;而amd64是x86架构&…...

Oracle查询优化:高效实现仅查询前10条记录的方法与实践

在 Oracle 中&#xff0c;实现仅查询前10条记录的四种方法 1. 使用 ROWNUM 查询 ROWNUM 是 Oracle 中的伪列&#xff0c;用于限制返回的行数。 SELECT * FROM table_name WHERE condition AND ROWNUM < 10;condition&#xff1a;查询条件。ROWNUM < 10&#xff1a;限制…...

【时时三省】(C语言基础)结构体内存对齐

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 我们已经掌握了结构体的基本使用了。现在我们深入讨论一个问题&#xff1a;计算结构体的大小。 这也是一个特别热门的考点&#xff1a;结构体内存对齐 示例&#xff1a; 第一个s如果根据字…...

工业物联网关

工业物联网关的定义与功能 定义&#xff1a;工业物联网关是一种在工业物联网&#xff08;IIoT&#xff09;系统中起到关键连接作用的设备。它位于工业现场设备&#xff08;如传感器、执行器等&#xff09;和上层的工业网络&#xff08;如企业内部网络、云平台等&#xff09;之间…...

Docker 安装 Yapi

Docker 安装系列 Docker已安装。 1、场景Yapi使用的MongoDB用户信息 1.1 创建自定义 Docker 网络 首先&#xff0c;创建一个自定义的 Docker 网络&#xff0c;以便 MongoDB 和 YApi 容器可以相互通信 [rootflexusx-328569 data]# docker network create yapi-networ…...

MaxEnt模型在物种分布模拟中如何应用?R语言+MaxEnt模型融合物种分布模拟、参数优化方法、结果分析制图与论文写作

目录 第一章 以问题导入的方式&#xff0c;深入掌握原理基础 第二章 常用数据检索与R语言自动化下载及可视化方法 第三章 R语言数据清洗与特征变量筛选 第四章 基于ArcGIS、R数据处理与进阶 第五章 基于Maxent的物种分布建模与预测 第六章 基于R语言的模型参数优化 第七…...

UDE连接不上miniwiggler

PLS 的UDE 软件搭配miniwiggler硬件用来调试英飞凌的单片机是个不错的选择&#xff0c;比如TC275、TC387等等。英飞凌官方开发板板载了miniwiggler&#xff0c;非常方便。 很多买了英飞凌官方开发板的同学可能会发现&#xff0c;使用英飞凌的mentool软件能连接上自己的板子&…...

Trimble X9三维激光扫描仪高效应对化工厂复杂管道扫描测绘挑战【沪敖3D】

化工安全关系到国计民生&#xff0c;近年来随着化工厂数字化改革不断推进&#xff0c;数字工厂逐步成为工厂安全管理的重要手段。而化工管道作为工厂设施的重要组成部分&#xff0c;由于其数量多、种类繁杂&#xff0c;一直是企业管理的重点和难点。 传统的化工管廊往往缺乏详…...

数据结构(Doubly Linked List双向链表)

1.前言&#xff1a; 在计算机科学的广袤领域中&#xff0c;数据结构犹如构建高楼大厦的基石&#xff0c;它们为高效地组织、存储和处理数据提供了坚实的框架。而双向链表作为一种重要且功能强大的数据结构&#xff0c;在众多算法与程序设计场景中都展现出了独特的魅力与价值。…...

【踩坑】修复报错libcurl.so.4、LIBFFI_BASE_7.0、libssl.so.3

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ libcurl.so.4&#xff1a; sudo apt install curl -y LIBFFI_BASE_7.0: conda install libffi3.3 -y libssl.so.3: sudo apt install -y openssl li…...

【Java实现MySQL 数据库导出 Excel 表的方法详解】

MySQL 数据库导出 Excel 表的方法详解 在日常开发中&#xff0c;我们经常需要将数据库中的数据导出为 Excel 文件&#xff0c;以便进行数据分析或分享给其他同事。本文将详细介绍如何从 MySQL 数据库导出数据并生成 Excel 文件&#xff0c;具体实现将基于 Java 语言和 Spring …...

CentOS 7 环境下常见的操作和配置

目录 1. CentOS 7 中的 vsftpd 配置与使用 安装与启动 vsftpd 配置 vsftpd&#xff08;/etc/vsftpd/vsftpd.conf&#xff09; 常见命令 2. 使用 yum 包管理器 3. 安全性与防火墙配置 开放端口 4. 使用 systemd 管理服务 5. SELinux 配置 查看 SELinux 状态 临时禁用…...

使用mtools搭建MongoDB复制集和分片集群

mtools介绍 mtools是一套基于Python实现的MongoDB工具集&#xff0c;其包括MongoDB日志分析、报表生成及简易的数据库安装等功能。它由MongoDB原生的工程师单独发起并做开源维护&#xff0c;目前已经有大量的使用者。 mtools所包含的一些常用组件如下&#xff1a; mlaunch支…...

基于 RNN(GRU, LSTM)+CNN 的红点位置检测(pytorch)

文章目录 1 项目背景2 数据集3 思路4 实验结果5 代码 1 项目背景 需要在图片精确识别三跟红线所在的位置&#xff0c;并输出这三个像素的位置。 其中&#xff0c;每跟红线占据不止一个像素&#xff0c;并且像素颜色也并不是饱和度和亮度极高的红黑配色&#xff0c;每个红线放大…...

35页PDF | 元数据与数据血缘落地实施(限免下载)

一、前言 这份报告详细介绍了元数据与数据血缘的概念、重要性以及在企业数据中台中的应用。报告阐述了数据中台的核心价值在于整合和管理体系内的数据&#xff0c;以提升数据资产化能力并支持业务决策。报告还涵盖了元数据的分类&#xff08;技术元数据和业务元数据&#xff0…...

Hyperf jsonrpc

依赖的 composer 包 composer require hyperf/json-rpc composer require hyperf/rpc-server composer require hyperf/rpc-client composer require hyperf/service-governance composer require hyperf/service-governance-consul composer require hyperf/service-gove…...

MYSQL PARTITIONING分区操作和性能测试

PARTITION OR NOT PARTITION IN MYSQl Bill Karwin says “In most circumstances, you’re better off using indexes instead of partitioning as your main method of query optimization.” According to RICK JAMES: “It is so tempting to believe that PARTITIONing wi…...

go引入skywalking

前置条件&#xff1a;安装好jdk11&#xff0c;linux服务器&#xff08;centos7.9&#xff09;&#xff0c;go版本&#xff08;我的是1.18&#xff0c;1.21都可以&#xff09; 1.下载skywalking Downloads | Apache SkyWalking 2.下载agent源码 Downloads | Apache SkyWalkin…...

如何通过实构与虚构实现动态交互的态、势、感、知的编排组合

通过 实构 与 虚构 实现 动态人机交互的态、势、感、知 的编排组合&#xff0c;是一个涉及多领域的复杂任务。这个问题的核心在于如何将现实和虚拟世界中的元素&#xff0c;特别是人的 态 &#xff08;状态&#xff09;、 势 &#xff08;趋势&#xff09;、 感 &#xff08;感…...

easyexcel 导出日期格式化

1.旧版本 在新的版本中formate已经被打上废弃标记。那么不推荐使用这种方式。 2.推荐方式 推荐使用另外一种方式【 Converter 】代码如下&#xff0c;例如需要格式化到毫秒【yyyy-MM-dd HH:mm:ss SSS】级别 创建一个公共Converter import com.alibaba.excel.converters.Conv…...

大模型Qwen面试内容整理-模型架构与原理

Qwen(通义千问)是阿里巴巴推出的大规模语言模型,其架构和原理与当前主流的大模型(如GPT、LLaMA等)有很多相似之处,但也具备一些独特的特点。下面是Qwen模型架构和原理的详细介绍: Transformer 架构 Qwen模型基于改进的 Transformer 架构,这是一种广泛用于自然语言处理(…...

Python 类的设计(以植物大战僵尸为例)

关于类的设计——以植物大战僵尸为例 一、设计类需满足的三要素1. 类名2. 属性和方法 二、以植物大战僵尸的为例的类的设计1. 尝试分类2. 创建对象调用类的属性和方法*【代码二】*3. 僵尸的继承 三、代码实现 一、设计类需满足的三要素 1. 类名 类名&#xff1a;某类事物的名…...

docker学习笔记(五)--docker-compose

文章目录 常用命令docker-compose是什么yml配置指令详解versionservicesimagebuildcommandportsvolumesdepends_on docker-compose.yml文件编写 常用命令 命令说明docker-compose up启动所有docker-compose服务&#xff0c;通常加上-d选项&#xff0c;让其运行在后台docker-co…...

第一个 JSP 程序

一个简单的 JSP 程序&#xff1a; 使用 IDEA 开发工具新建一个 maven 项目&#xff0c;具体操作如图所示&#xff1a; 配置 Tomcat 服务器 项目结构如下图所示&#xff1a; 3. 修改 index.jsp 页面的代码&#xff1a; <% page language"java" contentType&q…...

MongoDB分片集群搭建及扩容

分片集群搭建及扩容 整体架构 环境准备 3台Linux虚拟机&#xff0c;准备MongoDB环境&#xff0c;配置环境变量。一定要版本一致&#xff08;重点&#xff09;&#xff0c;当前使用 version4.4.9 配置域名解析 在3台虚拟机上执行以下命令&#xff0c;注意替换实际 IP 地址 e…...

Transformer简述和实现

Transformer 1、概述 (一)、诞生 自从2017年此文《Attention is All You Need》提出来Transformer后&#xff0c;便开启了大规模预训练的新时代&#xff0c;也在历史的长河中一举催生出了GPT、BERT这样的里程碑模型。 (二)、优势 相比之前占领市场的LSTM和GRU模型&#xf…...

使用Python3 连接操作 OceanBase数据库

注&#xff1a;使用Python3 连接 OceanBase数据库&#xff0c;可通过安装 PyMySQL驱动包来实现。 本次测试是在一台安装部署OBD的OceanBase 测试linux服务器上&#xff0c;通过python来远程操作OceanBase数据库。 一、Linux服务器通过Python3连接OceanBase数据库 1.1 安装pyth…...

vue3-hooks

hooks 把模块化 发挥到极致 命名规则&#xff1a; useDog.ts/useDog.js useXxx&#xff08;和xxx相关的所有内容&#xff09; 具体内容&#xff1a; export function que(){} 或者 export default function () { let dogList []; const getDog () > {} //向外…...

网络安全:构建数字世界的坚固防线

在当今数字化飞速发展的时代&#xff0c;网络已经渗透到我们生活的方方面面。从日常的社交娱乐、在线购物&#xff0c;到工作中的远程协作、数据存储与传输&#xff0c;网络无处不在。然而&#xff0c;随着网络的普及和应用的深入&#xff0c;网络安全问题也日益凸显&#xff0…...

Vision Transformer (ViT) 基本原理

Vision Transformer (ViT) 基本原理 flyfish Vision Transformer (ViT) 是一种基于 Transformer 架构的计算机视觉模型 一、ViT 的基本原理 ViT 的核心思想是将一张图像视为一组序列&#xff0c;将其嵌入到 Transformer 的输入中&#xff0c;通过自注意力机制捕获全局上下文…...

【青牛科技】拥有两个独立的、高增益、内部相位补偿的双运算放大器,可适用于单电源或双电源工作——D4558

概述&#xff1a; D4558内部包括有两个独立的、高增益、内部相位补偿的双运算放大器&#xff0c;可适用于单电源或双电源工作。该电路具有电压增益高、噪声低等特点。主要应用于音频信号放大&#xff0c;有源滤波器等场合。 D4558采用DIP8、SOP8的封装形式 主要特点&#xff…...

LCD与lvgl

LCD与lvgl 目录 LCD与lvgl 回顾 LCD 的驱动层讲解 1、LCD 的常见接口 2、我们的 LCD 的参数 3、LCD 的设备树说明 4、LCD 的设备树说明 5、如何移植 LCD 的驱动(重点) LCD 的应用层开发 1:LCD 应用开发->界面开发的方法 2:LVGL 模拟器安装 3:LVGL 工程创建和…...

大语言模型(2)--GPT-1

GPT-1是由OpenAI在2018年推出的第一代生成式预训练模型&#xff08;《Improving Language Understanding by Generative Pre-Training》&#xff09;&#xff0c;它采用了无监督预训练和有监督微调相结合的方法&#xff0c;以增强模型的通用任务求解能力。在此之前&#xff0c;…...

openstack内部rpc消息通信源码分析

我们知道openstack内部消息队列基于AMQP协议&#xff0c;默认使用的rabbitmq 消息队列。谈到rabbitmq&#xff0c;大家或许并不陌生&#xff0c;但或许会对oslo message有些陌生。openstack内部并不是直接使用rabbitmq&#xff0c;而是使用了oslo.message 。oslo.message 后端的…...

单端和差分信号的接线法

内容来源&#xff1a;【单端信号 差分信号与数据采集卡的【RSE】【 NRES】【 DIFF】 模式的连接】 此篇文章仅作笔记分享。 单端输入 单端信号指的是输入信号由一个参考端和一个信号端构成&#xff0c;参考端一般是地端&#xff0c;信号就是通过计算信号端口和地端的差值所得…...

服务器被ping的风险,如何开启和禁止ping?

允许服务器被ping&#xff08;即响应ICMP回显请求&#xff09;有其风险和好处。允许ping的主要好处是它可以帮助网络管理员快速检查服务器的连通性。然而&#xff0c;这也可能带来一些安全风险&#xff0c;例如&#xff1a; 暴露信息&#xff1a;响应ping请求可以让攻击者知道…...

pushgateway HA高可用方案

未经本人同意不得转载&#xff0c;若引用请附上原文链接。 项目使用flink来处理kafka中的无界流数据&#xff0c;采用的是flink on yarn的模式部署flink任务。最近做flink任务的监控过程中&#xff0c;踩了一些坑。下面是过程&#xff0c;只想看最终方案的直接拉到最后。 先说…...

在 Ubuntu Server 22.04 上安装 Docker 的详细步骤

本文档详细记录了在 Ubuntu Server 22.04 上安装 Docker 的完整过程&#xff0c;包括解决过程中遇到的问题。希望能对读者有所帮助。 安装过程&#xff0c;重点需要看官方文档。https://docs.docker.com/engine/install/ubuntu/ 步骤 1&#xff1a;卸载冲突的软件包 在安装 D…...

锻造船用发动机动力系统,铸强船舶“心脏”

船舶是海洋、湖泊及河流中重要的水上交通工具&#xff0c;不仅能够促进海上经济的发展&#xff0c;还能够保卫国家的制海权。船舶动力装置&#xff0c;也就是船舶的核心动力源——船用发动机动力系统对船舶的重要作用不言自明&#xff0c;关系到船舶的性能质量&#xff0c;能够…...