ScrollText:修订间差异
来自卡厄思梦境WIKI
创建页面,内容为“<style> .scroll-text { position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center; } .scroll-text .scroll-text-content { word-wrap: break-word; word-break: break-all; position: relative; width: 100%; text-align: center; } .scroll-text.has-scroll { align-items: flex-start; } .scroll-text.has-scroll .scroll-text-content { text-align: center; } .scroll-text .scroll-text-content.enable-scroll { a…” |
无编辑摘要 |
||
| (未显示同一用户的5个中间版本) | |||
| 第1行: | 第1行: | ||
<!-- ScrollText.html --> | |||
<style> | <style> | ||
.scroll-text { | .scroll-text { | ||
| 第4行: | 第5行: | ||
overflow: hidden; | overflow: hidden; | ||
display: flex; | display: flex; | ||
align-items: | align-items: flex-start; | ||
} | } | ||
/* 动画由 JS 动态设置 */ | |||
.scroll-text .scroll-text-content { | .scroll-text .scroll-text-content { | ||
word-wrap: break-word; | word-wrap: break-word; | ||
| 第13行: | 第14行: | ||
position: relative; | position: relative; | ||
width: 100%; | width: 100%; | ||
text-align: center; | text-align: center; | ||
will-change: transform; | |||
} | } | ||
.scroll-text .scroll-text-content | .scroll-text .scroll-text-content:hover { | ||
animation-play-state: paused; | animation-play-state: paused; | ||
} | } | ||
</style> | </style> | ||
| 第44行: | 第25行: | ||
<script> | <script> | ||
(function() { | (function() { | ||
var processedElements = new WeakSet(); | |||
function initScroll() { | function initScroll() { | ||
var wrappers = document.querySelectorAll('.scroll-text'); | var wrappers = document.querySelectorAll('.scroll-text'); | ||
wrappers.forEach(function(wrapper, index) { | wrappers.forEach(function(wrapper, index) { | ||
// 已完成动画绑定的元素跳过 | |||
if (processedElements.has(wrapper)) return; | |||
var content = wrapper.querySelector('.scroll-text-content'); | var content = wrapper.querySelector('.scroll-text-content'); | ||
if (!content || content.classList.contains(' | if (!content) return; | ||
// 不可见容器跳过(等待视图显示时再初始化) | |||
var rect = wrapper.getBoundingClientRect(); | |||
if (rect.width === 0 || rect.height === 0) return; | |||
var speed = parseFloat(content.getAttribute('data-speed')) || 10; | |||
var animationName = 'scrollText-' + index + '-' + Date.now(); | |||
setTimeout(function() { | |||
var contentHeight = content.scrollHeight; | |||
var wrapperHeight = wrapper.offsetHeight; | |||
var scrollDistance = contentHeight - wrapperHeight; | |||
// 内容未溢出,不绑定动画,也不标记为 processed,给后续机会 | |||
if (scrollDistance <= 0) return; | |||
// 动态注入 keyframes | |||
var style = document.createElement('style'); | |||
style.textContent = | |||
'@keyframes ' + animationName + ' {' + | |||
'0%{transform:translateY(0)}' + | |||
'100%{transform:translateY(-' + scrollDistance + 'px)}' + | |||
'}'; | |||
document.head.appendChild(style); | |||
// 根据字数/速度估算时长 | |||
var text = content.textContent || content.innerText || ''; | |||
var charCount = text.replace(/\s+/g, '').length; | |||
var duration = Math.max(speed, charCount / 8); | |||
// 设置动画属性 | |||
content.style.animationName = animationName; | |||
content.style.animationDuration = duration + 's'; | |||
content.style.animationTimingFunction = 'linear'; | |||
content.style.animationIterationCount = 'infinite'; | |||
content.style.animationPlayState = 'running'; | |||
// 仅在成功绑定动画后标记为已处理 | |||
processedElements.add(wrapper); | |||
}, 50); | |||
}); | |||
} | |||
// 监听自定义事件(视图显示后主动触发初始化) | |||
document.addEventListener('scrolltext:init', function () { | |||
setTimeout(initScroll, 50); | |||
}); | |||
// 监听 DOM 变化(模态和各子视图从隐藏到显示时触发) | |||
var observer = new MutationObserver(function(mutations) { | |||
var shouldInit = false; | |||
mutations.forEach(function(mutation) { | |||
if (mutation.type === 'attributes' && mutation.attributeName === 'style') { | |||
var el = mutation.target; | |||
var visible = el.style && el.style.display && el.style.display !== 'none'; | |||
if (visible && ( | |||
el.classList.contains('card-modal') || | |||
el.classList.contains('original-card-view') || | |||
el.classList.contains('inspiration-view') || | |||
el.classList.contains('god-inspiration-view') || | |||
el.classList.contains('subcards-view') || | |||
el.classList.contains('nested-subcards-view') || | |||
el.classList.contains('inspiration-subcards-view') || | |||
el.classList.contains('inspiration-nested-subcards-view') | |||
)) { | |||
shouldInit = true; | |||
} | |||
} | } | ||
if (mutation.addedNodes && mutation.addedNodes.length > 0) { | |||
shouldInit = true; | |||
} | } | ||
}); | }); | ||
} | |||
if (shouldInit) { | |||
setTimeout(initScroll, 100); | |||
} | |||
}); | |||
observer.observe(document.body, { | |||
childList: true, | |||
subtree: true, | |||
attributes: true, | |||
attributeFilter: ['style'] | |||
}); | |||
// 初始加载 | |||
if (document.readyState === 'loading') { | if (document.readyState === 'loading') { | ||
document.addEventListener('DOMContentLoaded', initScroll); | document.addEventListener('DOMContentLoaded', function() { | ||
setTimeout(initScroll, 100); | |||
}); | |||
} else { | } else { | ||
initScroll(); | setTimeout(initScroll, 100); | ||
} | |||
// MediaWiki 钩子 | |||
if (typeof mw !== 'undefined' && mw.hook) { | |||
mw.hook('wikipage.content').add(function() { | |||
setTimeout(initScroll, 100); | |||
}); | |||
} | } | ||
})(); | })(); | ||
</script> | </script> | ||
2025年10月16日 (四) 22:34的最新版本
<style> .scroll-text {
position: relative; overflow: hidden; display: flex; align-items: flex-start;
}
/* 动画由 JS 动态设置 */ .scroll-text .scroll-text-content {
word-wrap: break-word; word-break: break-all; position: relative; width: 100%; text-align: center; will-change: transform;
}
.scroll-text .scroll-text-content:hover {
animation-play-state: paused;
} </style>
<script> (function() {
var processedElements = new WeakSet();
function initScroll() {
var wrappers = document.querySelectorAll('.scroll-text');
wrappers.forEach(function(wrapper, index) {
// 已完成动画绑定的元素跳过
if (processedElements.has(wrapper)) return;
var content = wrapper.querySelector('.scroll-text-content');
if (!content) return;
// 不可见容器跳过(等待视图显示时再初始化)
var rect = wrapper.getBoundingClientRect();
if (rect.width === 0 || rect.height === 0) return;
var speed = parseFloat(content.getAttribute('data-speed')) || 10;
var animationName = 'scrollText-' + index + '-' + Date.now();
setTimeout(function() {
var contentHeight = content.scrollHeight;
var wrapperHeight = wrapper.offsetHeight;
var scrollDistance = contentHeight - wrapperHeight;
// 内容未溢出,不绑定动画,也不标记为 processed,给后续机会
if (scrollDistance <= 0) return;
// 动态注入 keyframes
var style = document.createElement('style');
style.textContent =
'@keyframes ' + animationName + ' {' +
'0%{transform:translateY(0)}' +
'100%{transform:translateY(-' + scrollDistance + 'px)}' +
'}';
document.head.appendChild(style);
// 根据字数/速度估算时长
var text = content.textContent || content.innerText || ;
var charCount = text.replace(/\s+/g, ).length;
var duration = Math.max(speed, charCount / 8);
// 设置动画属性
content.style.animationName = animationName;
content.style.animationDuration = duration + 's';
content.style.animationTimingFunction = 'linear';
content.style.animationIterationCount = 'infinite';
content.style.animationPlayState = 'running';
// 仅在成功绑定动画后标记为已处理
processedElements.add(wrapper);
}, 50);
});
}
// 监听自定义事件(视图显示后主动触发初始化)
document.addEventListener('scrolltext:init', function () {
setTimeout(initScroll, 50);
});
// 监听 DOM 变化(模态和各子视图从隐藏到显示时触发)
var observer = new MutationObserver(function(mutations) {
var shouldInit = false;
mutations.forEach(function(mutation) {
if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
var el = mutation.target;
var visible = el.style && el.style.display && el.style.display !== 'none';
if (visible && (
el.classList.contains('card-modal') ||
el.classList.contains('original-card-view') ||
el.classList.contains('inspiration-view') ||
el.classList.contains('god-inspiration-view') ||
el.classList.contains('subcards-view') ||
el.classList.contains('nested-subcards-view') ||
el.classList.contains('inspiration-subcards-view') ||
el.classList.contains('inspiration-nested-subcards-view')
)) {
shouldInit = true;
}
}
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
shouldInit = true;
}
});
if (shouldInit) {
setTimeout(initScroll, 100);
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['style']
});
// 初始加载
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
setTimeout(initScroll, 100);
});
} else {
setTimeout(initScroll, 100);
}
// MediaWiki 钩子
if (typeof mw !== 'undefined' && mw.hook) {
mw.hook('wikipage.content').add(function() {
setTimeout(initScroll, 100);
});
}
})(); </script>