Angular6 Div 围绕来自同一用户的数组
Posted
技术标签:
【中文标题】Angular6 Div 围绕来自同一用户的数组【英文标题】:Angular6 Div around Arrays from same user 【发布时间】:2018-12-23 20:40:54 【问题描述】:我有一些 Messenger 数据:
public messages = [
direction: 'me', // Required
user_id: 554, // Required
user: 'Sven', // Optional
avatar: 'urltoavatar', // Optional
message: 'Hi du alter babbsack!' // Optional
,
direction: 'others', // Required
user_id: 8774, // Required
user: 'Hannes', // Optional
avatar: 'urltoavatar', // Optional
message: 'Hey whats going on?' // Optional
,
direction: 'others', // Required
user_id: 8774, // Required
user: 'Hannes', // Optional
avatar: 'urltoavatar', // Optional
message: 'No Idea bro! This ' // Optional
];
我将这个插入到 Messenger 消息区:<mark6-messenger-message [messages]="messages" [avatarMe]="false" [avatarOthers]="true"></mark6-messenger-message>
<mark6-messenger-message>
的观点:
<ng-container *ngFor="let message of messages">
<div class="msg" [ngClass]="message.direction">
<div class="msg-avatar" *ngIf="(avatarMe && message.direction === 'me') || (avatarOthers && message.direction === 'others')">
<img [src]="message.avatar" [alt]="message.user">
</div>
<div class="msg-content">
<div class="msg-message">message.message</div>
</div>
</div>
</ng-container>
浏览器中的结果是这样的:(我在代码中更改了消息,不用担心)
现在的问题是,当 1 个人发送垃圾邮件时,我想从最新消息中删除头像。我想删除来自同一个人的 2 条消息之间的空格。像这样:
但由 2 个不同的人编写,它必须是这样的:
我很难弄清楚如何解决这个问题。我所问的只是告诉我,没有很多性能损失是没有办法的。我需要以某种方式执行此操作,仅使用数据direction
和user
(表示用户名)自动处理所有这些内容,或者我可能为user_id
添加一个字段,然后我有2个必填字段(@987654335 @ 和 user_id
) 我们的目标是让这一切变得尽可能简单和自动,因为这是我希望未来很多人会使用的开源库。我不想强迫他们做太多逻辑的事情。 :)
如果您需要检查其他文件或更多信息,这里是存储库:https://github.com/DevMonkeysDE/ngx-mark6/tree/master/projects/mark6-lib/src/lib/messenger
最好的事情是当每个人的每包消息都获得一个 div 容器时,我可以简单地使用 css:first-child 和 css:last-child。但是它必须动态地转换整个 html DOM 中的每条消息,这可能真的非常非常性能破坏。
【问题讨论】:
我会使用有条件的 CSS 元素来做到这一点,例如:删除消息之间的边距并在每条消息后添加一个“边距”div,并为其添加一个条件类以检查用户是否来自此index和过去的index是一样的,比选小margin class,如果不是选大padding class,和头像一样的东西,如果是同一个用户,不显示。 你能给我举个例子吗?我在这件事上很糟糕......而且你不认为将 div 包裹在来自同一方向和用户的消息周围更好吗?那么我只需要 1 个逻辑条件,其余的可以用简单的 css(第一个和最后一个孩子)来完成,但我以前从未见过有人将 div 实时包裹在元素周围。 (也许真的会破坏性能) 你不能单独在css中做,因为nth:child css不带条件,所以你无法匹配实时用户,如果我回家之前没有人回答,我会尽力为你提供举个简单的例子。 如果你有一个好的模型,结构与你想要生成的视图相匹配,一切都会变得更简单。您的描述表明您不想显示消息列表。您想要显示消息组列表,其中每个组有 1-N 条后续消息,所有消息均由单个用户发布。因此,使用 TypeScript 从您的消息中创建一组消息组(通过检测同一用户发布的后续消息)。然后你可以遍历每个组,并用一个头像显示每个组,并在这个组内,迭代该组的消息。 @JBNizet ,从他的话题和图片来看,他好像在进行某种聊天?因此,如果它是实时聊天,每次新消息到来时都运行这些分组,将占用大量资源。最好不要依赖控制器来执行此操作,因为它仅与视图有关。 【参考方案1】:一种可能的解决方案是使*ngIf
条件更复杂一些。
修改*ngFor
指令以跟踪消息索引,如下所示:*ngFor="let message of messages; let i=index"
然后您可以尝试类似*ngIf="(avatarMe && message.direction === 'me' && (messages[i+1].direction !== 'me') || (avatarOthers && message.direction === 'others' && (messages[i+1].user_id !== message.user_id))"
的方法,仅当下一条消息不是来自同一用户时才显示头像。
但是,它可能不适用于最后一条消息,因为它找不到 messages[i+1]
。
如果可能,另一种解决方案是修改messages
数组的数据结构以包含timestamp
(因为它是一个消息应用程序,所以跟踪时间更有意义)。然后我们可以按时间戳排序并显示具有最大时间戳的消息的头像。
【讨论】:
这对时间戳有意义,但我如何修改边距和边框半径等其他内容?因为这对我来说是最简单的解决方案,当消息组周围有一个 div 时。但是你认为这是因为性能没有选择吧? 如果我错了,请纠正我,div
和 class="msg-content"
负责显示包含消息的灰色圆形框。如果是这样,为什么不使用[ngClass]="msg-content: <<condition for NOT showing avatar>>, msg-content2: <<condition for showing avatar>>"
,其中 msg-content2 是具有不同边框的不同类?
头像在一个 div 中,类 msg-avatar
与 msg-content
的 div 处于同一 DOM 级别如果无法用 message group div
包装,那么我需要很多元素的条件.在msg-avatar
上隐藏头像(如果不是最后一条消息),在msg-content
上更改边框。 (首先删除边界半径底部,中间 div 删除所有边界半径,最后发布删除顶部边界半径:..)并在带有类 msg
的 div 上更改消息周围的边距......这很多逻辑......一个 div作为消息组工作将使一切变得更容易,因为我可以用 css 做所有事情。
这是一个权衡:要么修改数据结构,使模板更简单,要么保持数据结构简单,使模板复杂化,增加大量逻辑。我的建议是采用@JBNizet 的建议,将来自同一用户的消息分组。但是,我看不出如何区分用户 A 的消息(编号为例如:1、2、3),而另一个用户 B 的消息出现在 A 的第 3 条消息之前。在这种情况下,您需要将时间戳分别对 A 的 [1,2]
和 [3]
进行分组。我不确定是否有任何其他方式可以直接用消息组div
包装。
您可以在顶部有一个 div,在底部有一个 div,这是具有固定边距的分隔线,如果您上面的同一用户不应用该样式,除此之外,底部相同,只需检查下一条消息。我建议为每条消息创建一个新组件或指令,以更加有序和简单地处理所有这些逻辑。【参考方案2】:
您所追求的可以通过简单地比较 ngFor 循环中的当前 + 下一个消息方向并查看它们是否不同然后添加“最后一个”或任何您想要命名的类来完成。因为您本质上想要“这个方向的最后一个”消息。
<div [class]="message.direction" [ngClass]="last: messages[i+1] && messages[i+1].direction !== message.direction || isLast, message:true"
*ngFor="let message of messages; let isLast = last; let i = index;">
message.message
</div>
[class]="message.direction"
这将为我们提供消息的方向作为一个类 me
或 others
在你的情况下,非常简单。
现在让我解释一下“最后”类部分:
*ngFor="let message of messages; let isLast = last; let i = index;"
ngFor 指令暴露了一些局部变量,例如last
、first,
、index
,因此我们可以利用这一点并将我们的isLast
变量分配给 ngFor 循环中的last
局部变量,同时我们的i
变量将保存当前的index
ngFoor 循环。 Docs for ngFor
[ngClass]="last: messages[i+1] && messages[i+1].direction !== message.direction || isLast, message:true
如果我们的条件为真,我们使用 ngClass 指令来应用 last
类,在这种情况下,条件只是比较循环中的下一条消息 (messages[i+1].direction
) 是否与循环中的当前消息不同 @ 987654340@。唯一的问题是循环中的最后一条消息messages[i+1]
将是undefined
,这就是 or || isLast
检查通过的地方,因为这对于循环中的最后一条消息始终是正确的。 Docs for ngClass
顺便说一句,messages[i+1] && messages[i+1].direction
您需要这样做,因此只有在定义了messages[i+1]
时才短路条件检查方向,否则您的代码将在最后一项上崩溃。 You can read more about that in the javascript docs
对于显示/隐藏头像,只要你有 last
类,这只是简单的 css。
这是一个工作示例:https://stackblitz.com/edit/angular-gwqqee
希望对您有所帮助。
编辑:我忘了你有两个以上的用户,但同样的概念也适用,只需检查 user_id 而不是方向,请参阅更新的示例。
[ngClass]="
'message': true,
'last-from-direction': messages[i+1] && messages[i+1].direction !== message.direction || isLast,
'last-from-user': messages[i+1] && messages[i+1].user_id !== message.user_id || isLast
"
【讨论】:
非常感谢您的详细解释和令人敬畏的 stackbliz!这帮助我达到了我想要达到的目标。以上是关于Angular6 Div 围绕来自同一用户的数组的主要内容,如果未能解决你的问题,请参考以下文章
如何在 IBM Worklight 中重定向到同一页面但不同的 div/视图?
如何将请求标头信息传递给 Angular6 应用程序(JWT 通过请求标头发送)