Vue 封装公告滚动

文章目录

    • 需求
    • 分析
      • [1. 创建公告组件Notice.vue](#1. 创建公告组件Notice.vue)
      • [2. 注册全局组件](#2. 注册全局组件)
      • [3. 使用](#3. 使用)

需求

系统中需要有一个公告展示,且这个公告位于页面上方,每个页面都要看到

分析

1. 创建公告组件Notice.vue

  1. 第一种
    在你的项目的合适组件目录下(比如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>

亮点:

  1. 通过showNotice这个ref来控制公告栏是否显示,初始化为true表示默认显示。
    noticeText用来存放公告的具体文本内容,这里提供了一个示例文本,实际使用时可以替换成真实的公告内容来源(比如从接口获取等)。
  2. closeNotice方法用于点击关闭按钮时隐藏公告栏,即将showNotice设置为false。
    样式部分,设置公告栏为固定定位在页面顶部,设置了合适的背景色、文字颜色、内边距等,并且让关闭按钮靠右对齐,同时给了较高的z-index值确保它能显示在页面上方。
  1. 第二种
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>
相关推荐
LBJ辉6 分钟前
1. npm 常用命令详解
前端·npm·node.js
闲人陈二狗13 分钟前
Vue 3前端与Python(Django)后端接口简单示例
前端·vue.js·python
你挚爱的强哥13 分钟前
基于element UI el-dropdown打造表格操作列的“更多⌵”上下文关联菜单
javascript·vue.js·elementui
嶂蘅1 小时前
【调研】Android app动态更新launcher_icon
android·前端·程序员
LY8091 小时前
前端开发者的福音:用JavaScript实现Live2D虚拟人口型同步
前端·虚拟现实
林涧泣1 小时前
【Uniapp-Vue3】uniapp创建组件
前端·javascript·uni-app
Sinyu10121 小时前
Flutter 动画实战:绘制波浪动效详解
android·前端·flutter
pikachu冲冲冲1 小时前
vue权限管理(动态路由)
前端·vue.js
sunly_1 小时前
Flutter:文章详情页,渲染富文本
android·javascript·flutter
丁总学Java1 小时前
[Vue warn]: Unknown custom element:
javascript·vue.js·ecmascript