Angular 2 阅读更多指令
Posted
技术标签:
【中文标题】Angular 2 阅读更多指令【英文标题】:Angular 2 Read More Directive 【发布时间】:2016-10-15 14:48:19 【问题描述】:我需要在 Angular2 中构建一个 readmore 指令。该指令将使用“阅读更多”和“关闭”链接折叠和展开长文本块。不是基于字符数,而是基于指定的最大高度。
<div read-more [maxHeight]="250px" [innerhtml]="item.details">
</div>
任何人都可以指导在这种特定情况下获取/设置元素高度的最可靠方法是什么。
任何关于如何实施该特定指令的指南也将受到高度赞赏。
我需要构建这样的东西https://github.com/jedfoster/Readmore.js
解决方案:
在 Andzhik 的帮助下,我能够构建满足我要求的以下组件。
import Component, Input, ElementRef, AfterViewInit from '@angular/core';
@Component(
selector: 'read-more',
template: `
<div [innerHTML]="text" [class.collapsed]="isCollapsed" [style.height]="isCollapsed ? maxHeight+'px' : 'auto'">
</div>
<a *ngIf="isCollapsable" (click)="isCollapsed =! isCollapsed">Read isCollapsed? 'more':'less'</a>
`,
styles: [`
div.collapsed
overflow: hidden;
`]
)
export class ReadMoreComponent implements AfterViewInit
//the text that need to be put in the container
@Input() text: string;
//maximum height of the container
@Input() maxHeight: number = 100;
//set these to false to get the height of the expended container
public isCollapsed: boolean = false;
public isCollapsable: boolean = false;
constructor(private elementRef: ElementRef)
ngAfterViewInit()
let currentHeight = this.elementRef.nativeElement.getElementsByTagName('div')[0].offsetHeight;
//collapsable only if the contents make container exceed the max height
if (currentHeight > this.maxHeight)
this.isCollapsed = true;
this.isCollapsable = true;
用法:
<read-more [text]="details" [maxHeight]="250"></read-more>
如果有任何改进,请随时提出建议。
【问题讨论】:
Find currentHeight inside the setTimeout(_ => ..... ) 将消除一些窗口大小调整问题,同时角度运行变化检测。见***.com/questions/38930183/… 【参考方案1】:我制作了一个使用字符长度而不是 div 大小的版本。
import Component, Input, ElementRef, OnChanges from '@angular/core';
@Component(
selector: 'read-more',
template: `
<div [innerHTML]="currentText">
</div>
<a [class.hidden]="hideToggle" (click)="toggleView()">Read isCollapsed? 'more':'less'</a>
`
)
export class ReadMoreComponent implements OnChanges
@Input() text: string;
@Input() maxLength: number = 100;
currentText: string;
hideToggle: boolean = true;
public isCollapsed: boolean = true;
constructor(private elementRef: ElementRef)
toggleView()
this.isCollapsed = !this.isCollapsed;
this.determineView();
determineView()
if (!this.text || this.text.length <= this.maxLength)
this.currentText = this.text;
this.isCollapsed = false;
this.hideToggle = true;
return;
this.hideToggle = false;
if (this.isCollapsed == true)
this.currentText = this.text.substring(0, this.maxLength) + "...";
else if(this.isCollapsed == false)
this.currentText = this.text;
ngOnChanges()
this.determineView();
用法:
<read-more [text]="text" [maxLength]="100"></read-more>
【讨论】:
谢谢,这正是我所需要的! 带有html标签的内容呢? 我认为它应该适用于 html。它使用 [innerHTML] 指令 @DavidBracoly *** 旨在回答问题,而不是响应 github 之类的功能请求。如果您想添加这些功能,那么实现您想要的更改并不难。也就是说,如果你想添加这些功能,我给你我的贝宝账户,你可以转给我 200 美元,我会看看我能做什么:) 模板中的小改动...添加 *ngIf 到锚点...*ngIf="text.length >= this.maxLength"【参考方案2】:我认为您需要Component
而不是Directive
。 Components
更有意义,因为您需要添加 Read more 按钮/链接,即更新 DOM。
@Component(
selector: 'read-more',
template: `
<div [class.collapsed]="isCollapsed">
<ng-content></ng-content>
</div>
<div (click)="isCollapsed = !isCollapsed">Read more</div>
`,
styles: [`
div.collapsed
height: 250px;
overflow: hidden;
`]
)
export class ReadMoreComponent
isCollapsed = true;
用法:
<read-more>
<!-- you HTML goes here -->
</read-more>
【讨论】:
非常感谢 Andzhik 的回复。我对组件进行了一些更改:模板:` 阅读更多 `styles: [` div.collapsed height: 150px;溢出:隐藏; `] 我还添加了@Input() text: string;但我仍然需要一种方法来获取包含文本的 div 的高度,以便在此基础上我可以决定是显示还是隐藏阅读更多链接。 您可以使用ElementRef
ngcourse.rangle.io/handout/advanced-components/elementref.html 直接访问代表您的Component
的DOM 元素。 PS:如果您对我原来的回答满意,请采纳,谢谢。
我试过了,但是当我在构造函数或 ngAfterContentChecked 中登录控制台时,它返回 undefined console.log(this.el.nativeElement.height);我也试过 @HostBinding('style.height') private height: string;但它也未定义。
看起来更好的生命周期钩子是ngAfterViewInit
,你需要得到this.el.nativeElement.offsetHeight
而不是...height
。 height
是 `this.el.nativeElement.style' 的成员,此时没有任何价值。
非常感谢 Andzhik,你非常有帮助,我已经在下面发布了我的最终阅读更多组件,如果有任何改进,请提出建议。【参考方案3】:
在 Andzhik 的帮助下,我能够构建满足我要求的以下组件。
import Component, Input, ElementRef, AfterViewInit from '@angular/core';
@Component(
selector: 'read-more',
template: `
<div [innerHTML]="text" [class.collapsed]="isCollapsed" [style.height]="isCollapsed ? maxHeight+'px' : 'auto'">
</div>
<a *ngIf="isCollapsable" (click)="isCollapsed =! isCollapsed">Read isCollapsed? 'more':'less'</a>
`,
styles: [`
div.collapsed
overflow: hidden;
`]
)
export class ReadMoreComponent implements AfterViewInit
//the text that need to be put in the container
@Input() text: string;
//maximum height of the container
@Input() maxHeight: number = 100;
//set these to false to get the height of the expended container
public isCollapsed: boolean = false;
public isCollapsable: boolean = false;
constructor(private elementRef: ElementRef)
ngAfterViewInit()
let currentHeight = this.elementRef.nativeElement.getElementsByTagName('div')[0].offsetHeight;
//collapsable only if the contents make container exceed the max height
if (currentHeight > this.maxHeight)
this.isCollapsed = true;
this.isCollapsable = true;
用法:
<read-more [text]="details" [maxHeight]="250"></read-more>
【讨论】:
【参考方案4】:import Component, Input,OnChanges from '@angular/core';
@Component(
selector: 'read-more',
template: `
<div [innerHTML]="currentText"></div>
<span *ngIf="showToggleButton">
<a (click)="toggleView()">Read isCollapsed? 'more':'less'</a>
</span>`
)
export class ReadMoreDirective implements OnChanges
@Input('text') text: string;
@Input('maxLength') maxLength: number = 100;
@Input('showToggleButton')showToggleButton:boolean;
currentText: string;
public isCollapsed: boolean = true;
constructor(
//private elementRef: ElementRef
)
toggleView()
this.isCollapsed = !this.isCollapsed;
this.determineView();
determineView()
if (this.text.length <= this.maxLength)
this.currentText = this.text;
this.isCollapsed = false;
return;
if (this.isCollapsed == true)
this.currentText = this.text.substring(0, this.maxLength) + "...";
else if(this.isCollapsed == false)
this.currentText = this.text;
ngOnChanges()
if(!this.validateSource(this.text))
//throw 'Source must be a string.';
console.error('Source must be a string.');
else
this.determineView();
validateSource(s)
if(typeof s !== 'string')
return false;
else
return true;
和用法
<read-more [text]="this is test text" [maxLength]="10" [showToggleButton]="true"></read-more>
【讨论】:
没有 CSS 的最佳答案【参考方案5】:我再次用动态数据和完全控制解决了这些类型的问题。
<div class="Basic-Info-para">
<p>
<span *ngIf="personalBasicModel.professionalSummary.length>200" id="dots">
personalBasicModel.professionalSummary | slice:0:200 ...
</span>
<span id="more">personalBasicModel.professionalSummary
</span>
</p>
</div>
这里,personalBasicModel.professionalSummary 包含字符串。像任何文本一样。slice:0:200 = 对长度为 200 个字符的拼接字符串使用切片管道。你可以根据你的要求改变长度。 id="dots" & id="more" 两个重要的东西。
<div class="Basic-Info-SeeMore">
<button class="SeeMore"(click)="showMore(paasValueOn_SeeMoreBtn)">
showLess_More
</button>
</div>
这里我们定义了一个带有动态文本的按钮(多看少看),带有点击事件。
//------------------------------------ ts 文件 --------- --------------------------//
定义变量
showLess_More : string = "SEE MORE...";paasValueOn_SeeMoreBtn : boolean = true;
当用户点击查看更多按钮时触发事件(方法)
showMore(data:boolean)
if(data)
$("#dots").css('display', 'none');
$("#more").css('display', 'inline');
this.showLess_More = "SEE LESS ...";
this.paasValueOn_SeeMoreBtn = false;
else
$("#dots").css('display', 'inline');
$("#more").css('display', 'none');
this.showLess_More = "SEE MORE...";
this.paasValueOn_SeeMoreBtn = true;
【讨论】:
【参考方案6】:如果要在不剪切任何单词的情况下将文本显示到最大字符数,请更改此行代码:
this.currentText = this.text.substring(0, this.maxLength) + "...";
收件人:
this.currentText = this.text.substring(0, this.maxLength);
this.currentText = this.currentText.substr(0, Math.min(this.currentText.length, this.currentText.lastIndexOf(" ")))
this.currentText = this.currentText + "..."
【讨论】:
【参考方案7】:只是对@Andrei Zhytkevich 代码的轻微改进 (对降价有用)
import
Component,
AfterViewInit,
ViewChild,
ElementRef,
Attribute,
ChangeDetectionStrategy from '@angular/core';
@Component(
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'ui-read-more',
template: `
<div [class.collapsed]="isCollapsed" [style.height]="_height">
<div #wrapper>
<ng-content></ng-content>
</div>
</div>
<div class="read-more">
<button
type="button"
class="btn btn-light" (click)="onIsCollapsed()">isCollapsed ? 'More' : 'Less'</button>
</div>
`,
styles: [`
:host
display: block;
.collapsed
overflow: hidden;
padding-bottom: 1rem;
.read-more
display: flex;
justify-content: flex-end;
`]
)
export class UiReadMoreComponent implements AfterViewInit
@ViewChild('wrapper') wrapper: ElementRef;
isCollapsed: boolean = true;
private contentHeight: string;
private _height: string;
constructor(@Attribute('height') public height: string = '')
this._height = height;
ngAfterViewInit()
this.contentHeight = this.wrapper.nativeElement.clientHeight + 'px';
onIsCollapsed()
this.isCollapsed = !this.isCollapsed;
this._height = this.isCollapsed ? this.height : this.contentHeight;
用法
<ui-read-more >
<ngx-md>
post.content
</ngx-md>
</ui-read-more>
【讨论】:
【参考方案8】:谢谢,由于控制台错误,我在 NgOnInit 上进行了一些更改。 它有一些细微的变化,并且适用于 Angular 6。
@Component(
selector: 'app-read-more',
template: `
<div id="textCollapse" [innerHTML]="text" [class.collapsed]="isCollapsed" [style.height]="isCollapsed ? maxHeight+'px' : 'auto'">
</div>
<a *ngIf="isCollapsible" (click)="isCollapsed =! isCollapsed">Read isCollapsed ? 'more':'less'</a>
`,
styles: [`
div.collapsed
overflow: hidden;
a
color: #007bff !important;
cursor: pointer;
`]
)
export class ReadMoreComponent implements OnInit
// the text that need to be put in the container
@Input() text: string;
// maximum height of the container
@Input() maxHeight: number;
// set these to false to get the height of the expended container
public isCollapsed = false;
public isCollapsible = false;
constructor(private elementRef: ElementRef)
ngOnInit()
const currentHeight = document.getElementById('textCollapse').offsetHeight;
if (currentHeight > this.maxHeight)
this.isCollapsed = true;
this.isCollapsible = true;
如您所见,我更改了const current Height = document.getElementById('textCollapse').offsetHeight;
【讨论】:
【参考方案9】:你可以使用这个插件。
很简单,只需要传递[text]
和[textLength]
就可以默认显示
https://www.npmjs.com/package/nga-read-more
【讨论】:
【参考方案10】:线高方法:-
lineheight
和很少的计算和一些 css text-overflow: ellipsis;
完成这项工作。
.css
.descLess
margin-bottom: 10px;
text-overflow: ellipsis;
overflow: hidden;
word-wrap: break-word;
display: -webkit-box;
line-height: 1.8; <==== adjust line-height...a/q to your need
letter-spacing: normal;
white-space: normal;
max-height: 52px; <==== 250px etc:-
width: 100%;
/* autoprefixer: ignore next */
-webkit-line-clamp: 2; <==== clamp line 2...or 3 or 4 or 5...
-webkit-box-orient: vertical;
.html
<div class="col-12 rmpm">
<div id="descLess" *ngIf="seeMoreDesc === 'false'" class="descLess col-12 rmpm">
inputData?.desc
</div>
<div *ngIf="seeMoreDesc === 'true'" class="col-12 rmpm" style="margin-bottom: 10px;line-height: 1.8;">
<!--Use Line height here-->
inputData?.desc
</div>
<span class="seeMore" *ngIf="seeMoreDesc === 'false' && lineHeightDesc > 21"
(click)="updateSeeMore('seeMoreDesc', 'true')">
See More
</span>
<span class="seeMore" *ngIf="seeMoreDesc === 'true'"
(click)="updateSeeMore('seeMoreDesc', 'false')">
See Less
</span>
</div>
.ts
declare const $:any;
seeMoreDesc = 'false';
seeMore = '';
inputData =
'desc':'Lorem Ipusme dummy text..................'
constructor(
private eRef: ElementRef,
private cdRef : ChangeDetectorRef
)
ngAfterViewChecked()
// pass line height here
this.lineHeightDesc = (Number($('#descLess').height()) / 1.8);
this.cdRef.detectChanges();
public updateSeeMore(type, action)
if (type === 'seeMoreDesc')
this.seeMoreDesc = action;
this.cdRef.detectChanges();
else if (type === 'seeMore')
this.seeMore = action;
this.cdRef.detectChanges();
【讨论】:
以上是关于Angular 2 阅读更多指令的主要内容,如果未能解决你的问题,请参考以下文章