文章目录
需求
系统中需要有一个公告展示,且这个公告位于页面上方,每个页面都要看到
分析
1. 创建公告组件Notice.vue
- 第一种
在你的项目的合适组件目录下(比如components目录)创建Notice.vue文件,内容如下:
html
<template>
<div class="notice-bar-container">
<div class="notice-bar" v-if="showNotice">
<div class="notice-content-wrapper">
<div class="notice-content" ref="noticeContent">
<span v-if="isScrolling">{{ noticeText }}</span>
</div>
</div>
<button class="close-btn" @click="closeNotice">×</button>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, nextTick, onBeforeMount } from 'vue';
import { onMounted as onWindowMounted } from '@vue/runtime-core';
// 控制公告栏是否显示的响应式变量
const showNotice = ref(true);
// 公告内容
const noticeText = ref('这里是公告内容示例,可替换哦');
const noticeContent = ref(null);
// 用于存储页面宽度
const pageWidth = ref(window.innerWidth);
// 用来存储滚动定时器
const scrollInterval = ref(null);
// 控制公告内容是否开始滚动展示的变量
const isScrolling = ref(false);
// 关闭公告的方法
const closeNotice = () => {
showNotice.value = false;
if (scrollInterval.value) {
clearInterval(scrollInterval.value);
}
};
// 在组件挂载前获取页面宽度(首次)
onBeforeMount(() => {
pageWidth.value = window.innerWidth;
});
// 当窗口大小变化时,更新页面宽度
onWindowMounted(() => {
window.addEventListener('resize', () => {
pageWidth.value = window.innerWidth;
});
});
onMounted(() => {
nextTick(() => {
// 获取滚动内容的宽度
const contentWidth = noticeContent.value.offsetWidth;
// 设置外层容器宽度为页面宽度的50%,并开启滚动
noticeContent.value.parentNode.parentNode.style.width = `${pageWidth.value * 0.5}px`;
noticeContent.value.parentNode.parentNode.style.marginLeft = 'auto';
noticeContent.value.parentNode.parentNode.style.marginRight = 'auto';
noticeContent.value.parentNode.parentNode.style.overflow = 'hidden';
// 克隆一份内容用于滚动衔接
const cloneNode = noticeContent.value.cloneNode(true);
noticeContent.value.parentNode.appendChild(cloneNode);
// 滚动动画逻辑
let scrollDistance = pageWidth.value * 0.5;
const scrollSpeed = 2; // 调整滚动速度,可按需修改
scrollInterval.value = setInterval(() => {
scrollDistance -= scrollSpeed;
if (scrollDistance < -contentWidth) {
scrollDistance = pageWidth.value * 0.5;
}
noticeContent.value.style.transform = `translateX(${scrollDistance}px)`;
// 隐藏页面展示的文字,只展示滚动的文字
noticeContent.value.parentNode.style.overflow = 'hidden';
// 清除公告内容区域可能存在的文本节点(除了绑定的 noticeText 内容)
const childNodes = noticeContent.value.childNodes;
for (let i = 0; i < childNodes.length; i++) {
if (childNodes[i].nodeType === 3 && childNodes[i].textContent.trim()!== noticeText.value.trim()) {
noticeContent.value.removeChild(childNodes[i]);
}
}
// 开始滚动时设置 isScrolling 为 true,展示公告内容
isScrolling.value = true;
}, 30);
});
});
</script>
<style scoped>
.notice-bar-container {
width: 100%;
display: flex;
justify-content: center;
}
.notice-bar {
position: fixed;
top: 0;
background-color: #f8d7da;
color: #721c24;
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 999;
}
.notice-content-wrapper {
flex: 1;
overflow: hidden;
}
.notice-content {
white-space: nowrap;
display: inline-block;
}
.close-btn {
background-color: transparent;
border: none;
color: inherit;
font-size: 16px;
cursor: pointer;
}
</style>
亮点:
- 通过showNotice这个ref来控制公告栏是否显示,初始化为true表示默认显示。
noticeText用来存放公告的具体文本内容,这里提供了一个示例文本,实际使用时可以替换成真实的公告内容来源(比如从接口获取等)。- closeNotice方法用于点击关闭按钮时隐藏公告栏,即将showNotice设置为false。
样式部分,设置公告栏为固定定位在页面顶部,设置了合适的背景色、文字颜色、内边距等,并且让关闭按钮靠右对齐,同时给了较高的z-index值确保它能显示在页面上方。
- 第二种
html
<template>
<div v-if="visible" class="announcement-container">
<div class="announcement-content" :style="{ width: contentWidth + 'px' }">
<span>{{ message }}</span>
</div>
<button class="close-btn" @click="closeAnnouncement">x</button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const visible = ref(true); // 公告是否显示
const message = ref("这是一条滚动公告,您可以设置任何内容显示在这里。");
const contentWidth = ref(0); // 动态计算公告内容的宽度
// 页面加载时计算公告的宽度
onMounted(() => {
contentWidth.value = window.innerWidth / 2; // 公告宽度为页面宽度的50%
});
// 关闭公告的逻辑
const closeAnnouncement = () => {
visible.value = false;
};
</script>
<style scoped>
.announcement-container {
position: fixed;
top: 22%;
left: 50%;
transform: translateX(-50%);
width: 50%;
background-color: #ff9800;
color: white;
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 9999;
font-size: 16px;
border-radius: 5px;
overflow: hidden;
}
.announcement-content {
white-space: nowrap;
overflow: hidden;
animation: scroll-left 20s linear infinite;
}
@keyframes scroll-left {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(-100%);
}
}
.close-btn {
background: transparent;
border: none;
color: white;
font-size: 20px;
cursor: pointer;
padding: 5px;
margin-left: 10px;
}
</style>
2. 注册全局组件
在你的项目的入口文件(比如main.js或者main.ts,如果是 Vue 3 + TypeScript 的话)中进行全局组件注册,示例如下:
javascript
import { createApp } from 'vue';
import App from './App.vue';
import Notice from './components/Notice.vue';
const app = createApp(App);
// 注册全局公告组件
app.component('Notice', Notice);
app.mount('#app');
通过app.component方法将Notice组件注册为全局组件,这样在项目的任何页面(组件)中都可以直接使用标签来展示公告栏了。
3. 使用
例如在App.vue或者其他页面组件中使用:
html
<template>
<div id="app">
<Notice />
<router-view></router-view>
</div>
</template>