我目前正在致力于在 Svelte 框架中实现注释。您可以在下面的代码中看到我正在使用的数据结构。可视化工作完美,内容样式基于字符索引。然而,我在为用户交互添加“on:click”功能时面临着挑战。我的困难在于整个样式是在 JavaScript 函数中定义的,我需要循环注释,考虑它们的开始和结束索引。
非常感谢您帮助添加“on:click”功能,以便我可以集成其他功能,例如在用户与注释交互时修改或删除注释。这种方法看起来合适吗,或者有什么错误吗?非常感谢您的帮助。
<script>
// @ts-nocheck
let colorAnnotation = '#ff798090';
let colorAnnotationText = '#ee456789';
let annotatedData = {
'text': `
The sun hung low in the sky, casting long shadows across the quiet street. The sound of children playing echoed in the distance, and a gentle breeze rustled the leaves of the trees. It was a peaceful evening, perfect for a leisurely walk and some quiet reflection.
As I strolled down the cobblestone path, the aroma of freshly baked bread wafted from a nearby bakery, tempting my senses. I couldn't resist stepping inside, where warm smiles greeted me, and I indulged in a warm baguette, still soft from the oven. With each bite, I felt a sense of contentment wash over me, savoring the simple pleasures of life on this serene evening.
`,
'annotations': [
{
'label': 'action',
'start_offset': 23,
'end_offset': 52,
},
{
'label': 'comedy',
'start_offset': 177,
'end_offset': 206,
},
{
'label': 'white',
'start_offset': 272,
'end_offset': 308,
},
{
'label': 'location',
'start_offset': 132,
'end_offset': 166,
},
{
'label': 'description',
'start_offset': 313,
'end_offset': 348,
}
]
};
let formattedText = formatText(annotatedData.text, annotatedData.annotations);
let isPopupMenuVisible = false;
let popupMenuX = 0;
let popupMenuY = 0;
function popUpMenu(label, x, y) {
// Here you can implement logic to show a pop-up menu
// For this example, we'll just alert the label
alert(`You clicked on: ${label}`);
isPopupMenuVisible = true;
popupMenuX = x;
popupMenuY = y;
}
function formatText(text, annotations) {
// Sort annotations by start_offset in ascending order
annotations.sort((a, b) => a.start_offset - b.start_offset);
let result = [];
let lastIndex = 0;
annotations.forEach(annotation => {
const start = annotation.start_offset;
const end = annotation.end_offset;
// Text before the annotation
result.push(text.substring(lastIndex, start));
// Span for the annotation with Svelte on:click handler
result.push(`
<span style="background-color:${colorAnnotation}; cursor: pointer" on:click={() => popUpMenu('${annotation.label}', event.clientX, event.clientY)}
>
<span style="position:relative; background-color:white; color: ${colorAnnotationText};">${annotation.label}</span>
${text.substring(start, end)}
</span>
`);
lastIndex = end;
});
// Text after the last annotation
result.push(text.substring(lastIndex));
return result.join('');
}</script>
<div>
{@html formattedText}
</div>
<div class="popup-menu" style="left:{popupMenuX}px; top:{popupMenuY}px; display: {isPopupMenuVisible ? 'block' : 'none'}">
<!-- Add your pop-up menu content here -->
<button on:click={() => isPopupMenuVisible = false}>Close</button>
</div>
<style>
/* Define your styles here */
.popup-menu {
position: absolute;
background-color: white;
border: 1px solid #ccc;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
z-index: 999;
padding: 10px;
}
</style>
您不能在动态插入的 HTML 中使用
on:event
,这是需要编译的 Svelte 特定语法。
使用 Svelte 标记/单独的组件,或使用事件冒泡来处理 Svelte 中静态定义的父元素上的所有注释事件。
如果您想使用标记/组件,您可以将数据预处理为标记,然后使用
#each
来渲染它们,而不是使用 @html
。例如
{#each tokens as token}
{#if token.type == 'text'}
{token.text}
{:else if token.type == 'annotation'}
<!-- Use button, otherwise accessibility sucks -->
<button type="button" class="annotation"
on:click={() => onAnnotationClick(token)}>
{token.text}
</button>
...
{/each}
对于活动委托:
<div on:click={onWrapperClick}>
{@html formattedText}
</div>
// when adding annotations
result.push(`
<button type="button" ... data-annotation-id="${...}">
${text.substring(start, end)}
</button>
`);
// handle clicks
function onWrapperClick(e) {
const annotation = e.target.closest('[data-annotation-id]');
if (!annotation)
return;
const id = annotation.dataset.annotationId;
// [do stuff]
}
要删除默认按钮样式,请先取消所有设置:
.annotation { all: unset; }
.annotation:focus-visible { outline: auto } /* restore focus display */