我正在从事个人 Angular 项目(使用 Angular Material),但我找不到此问题的解决方案。
例如,我有一个像这样的长文本:
当你采取闪避动作时,你完全专注于躲避 攻击。直到你的下一个回合开始之前,进行的任何攻击检定 如果你能看到攻击者,并且你做了,那么对你有缺点 敏捷节省投掷具有优势。如果您发生以下情况,您将失去这项福利: 无行为能力(如条件中所述)或者您的速度下降 到 0.
我有一些关键词,这里是缺点,优点是无能力。我想将字体设置为粗体并添加一个工具提示来为每个关键字添加一个小解释。
我可以用管道将字体加粗,但我找不到为关键字添加工具提示的解决方案。使用innerHTML不起作用,这是我当前的解决方案:
<div innerHTML="description | transformKeyWord"></div>
还有我的烟斗:
transform(value: string, ...args: unknown[]): unknown {
let result = value
result = result.replace('advantage', '<span matTooltip="Advantage description">advantage</span>')
result = result.replace('incapacitated', '<b [matTooltip]="Incapacitated description">incapacitated</b>')
return result;
}
我认为这不是使用带有innerHTML的管道的好解决方案,这就是我寻求帮助的原因。
TLDR:https://stackblitz.com/edit/angular-ivy-86uxvs?file=src/app/app.component.html
在我看来,每个关键字都是一个
object
,带有 word
和 tooltip
。所以我将为此定义架构。
export type keyword = {
word: string;
tooltip: string;
};
我将在对象中定义关键字以便于查找:
keywords: { [key: string]: keyword } = {
disadvantage: {
word: 'disadvantage',
tooltip: 'advantage description',
},
incapacitated: {
word: 'incapacitated',
tooltip: 'incapacitated description',
},
};
我认为最好的方法是将字符串拆分为字符串和关键字的数组,这样我们就可以按顺序将它们打印到html中。这是一个可以做到这一点的函数 - 我将所有这些都放在一个服务中,因为它看起来很合适。
toDynamicText(text: string): (string | keyword)[] {
const res: (string | keyword)[] = [];
const tokens = text.split(' ');
let i = 0;
for (const token of tokens) {
let keyword = this.keywords[token.toLowerCase()]; //undefined if word is not a keyword
if (keyword) {
i = res.push(keyword);
} else {
if (!res[i]) res[i] = token;
else res[i] += ' ' + token;
}
}
return res;
}
输出数组如下所示:
[
"When you take the Dodge action, you focus entirely on avoiding attacks. Until the start of your next turn, any Attack roll made against you has",
{
"word": "disadvantage",
"tooltip": "advantage description"
},
"if you can see the attacker, and you make Dexterity Saving Throws with advantage. You lose this benefit if you are",
{
"word": "incapacitated",
"tooltip": "incapacitated description"
},
"(as explained in Conditions ) or if your speed drops to 0. "
]
这是如何使用它的示例:
text =
'When you take the Dodge action, you focus entirely on avoiding attacks. ' +
'Until the start of your next turn, any Attack roll made against you has disadvantage if you can see the attacker, ' +
'and you make Dexterity Saving Throws with advantage. ' +
'You lose this benefit if you are Incapacitated (as explained in Conditions ) or if your speed drops to 0. ';
dynamicText: (string | keyword)[] = [];
constructor(private dynamicTextService: DynamicTextService) {}
ngOnInit(): void {
this.dynamicText = this.dynamicTextService.toDynamicText(this.text);
}
isString(token: any) {
return typeof token === 'string';
}
//Typescript compiler wants a typecast, so we have two helper functions
getTooltip(token: string | keyword) {
return (token as keyword).tooltip;
}
getWord(token: string | keyword) {
return (token as keyword).word;
}
<p>
<ng-container *ngFor="let token of dynamicText">
<ng-container *ngIf="isString(token)">{{ token }}</ng-container>
<ng-container *ngIf="!isString(token)"
><b [matTooltip]="getTooltip(token)" style="cursor: pointer">
{{ getWord(token) }}
</b></ng-container
>
</ng-container>
</p>
您可以通过在尝试返回
tooltip
和 word
属性之前确保它们存在来使其更加健壮。
我会将其作为一个组件,并以
text
作为输入变量。
我成功用 HTML 创建了自定义工具提示,使用 MouseOver 调用该方法,并通过 ClassName 更改了innerHTML。
<mat-icon
class="tw-cursor-pointer"
#tooltip="matTooltip"
matTooltip="sample text"
[matTooltipPosition]="tooltipPosition"
(mouseover)="onHover()">
info
</mat-icon>
....
onHover(): void {
setTimeout(() => {
document.getElementsByClassName('mdc-tooltip__surface')[0].innerHTML =
`<span class="tw-font-bold">This is a tooltip</span> <br/><br/>`;
});
}