DOM操作とCSS Transformを使った基本的な実装
この方法は、テキストコンテンツをラップする要素のCSS transformプロパティを直接操作してスクロール効果を作成します。
テンプレート構造
<div class="marquee-container" ref="container">
<div class="scrolling-content" ref="content">
<p class="display-text">{{displayContent}}</p>
<p class="measurement-text" ref="measurement"></p>
</div>
<p class="width-reference" ref="widthRef">{{displayContent}}</p>
</div>
コンポーネントロジック
export default {
name: 'MarqueeComponent',
props: {
items: {
type: Array,
default: () => []
}
},
data() {
return {
animationTimer: null,
displayContent: '',
currentPosition: 0
};
},
created() {
this.initializeContent();
},
mounted() {
this.startScrolling();
},
methods: {
initializeContent() {
if (this.items.length > 0) {
this.displayContent = this.items.join(' ');
}
},
startScrolling() {
const containerWidth = this.$refs.container.clientWidth;
const textWidth = this.$refs.widthRef.scrollWidth;
if (textWidth <= containerWidth) return;
const measurementElement = this.$refs.measurement;
measurementElement.textContent = this.displayContent;
this.animationTimer = setInterval(() => {
this.currentPosition -= 1;
if (-this.currentPosition >= textWidth) {
this.currentPosition = containerWidth;
}
this.$refs.content.style.transform = `translateX(${this.currentPosition}px)`;
}, 20);
}
},
beforeDestroy() {
if (this.animationTimer) {
clearInterval(this.animationTimer);
}
}
};
スタイル設定
.marquee-container {
width: 100%;
overflow: hidden;
position: relative;
}
.scrolling-content {
display: flex;
}
.display-text {
margin-right: 0.16rem;
}
.width-reference {
word-break: keep-all;
white-space: nowrap;
position: absolute;
opacity: 0;
top: 0;
}
p {
word-break: keep-all;
white-space: nowrap;
font-size: 0.28rem;
}
requestAnimationFrameとCSSマージンを使ったアニメーション実装
このアプローチは、ブラウザのアニメーションAPIを活用してよりスムーズなスクロールを実現します。
テンプレート構造
<div class="animation-wrapper">
<div class="scrolling-text" style="color: rgb(255, 121, 1); font-size: 16px;">
<i class="el-icon-warning-outline" style="font-weight: 500;" />
{{notificationText}}
</div>
</div>
スクロール制御ロジック
methods: {
startTextAnimation(scrollText) {
const wrapper = document.querySelector(".animation-wrapper");
const textElement = document.querySelector(".scrolling-text");
textElement.textContent += scrollText;
const textWidth = textElement.offsetWidth;
let offset = wrapper.offsetWidth;
const animate = () => {
if (offset <= -textWidth) {
textElement.style.marginLeft = '0px';
offset = wrapper.offsetWidth;
}
textElement.style.marginLeft = `${offset--}px`;
window.requestAnimationFrame(animate);
};
window.requestAnimationFrame(animate);
}
}
コンテナスタイル
.animation-wrapper {
display: flex;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
}
.scrolling-text {
padding: 0 5px;
white-space: nowrap;
}
シームレスなループ表示のためのテキスト幅計算
動的にテキストコンテンツを変更する場合、正確な幅の計算が重要です。
methods: {
calculateTextWidth(textContent, fontSize) {
const doubleByteCount = (textContent.match(/[^\x00-\xff]/g) || []).length;
const singleByteCount = textContent.length - doubleByteCount;
const totalWidth = (doubleByteCount * 2 + singleByteCount) * fontSize / 2;
return totalWidth + 5;
}
}
このメソッドは、全角文字を2文字分、半角文字を1文字分として計算し、正確なピクセル幅を返します。