Create read more link in AngularJS

前端 未结 4 1090
后悔当初
后悔当初 2020-12-28 21:58

I want to create a link with read more text. if there are more than 3 lines in a paragraph this link should be visible and clicking on this it show display all the lines.

4条回答
  •  被撕碎了的回忆
    2020-12-28 22:46

    There can be some workaround.

    basic idea is like this

     1. at first, use javascript to calculate the original height
     2. if higher than 3 lines , set the overflow to hidden and show a button. The button is used to toggle state
     3.  if not,  do nothing
    

    About the button.

    If the button is out of text area, it's no problem for you I think. If you need the button inline within the element, there are 2 possibilitis.

    1. if you want it position fixed at right-bottom, create a gradient background for the button, fade-out effect. It looks nice and very simple.

      here is jsfiddle: http://jsfiddle.net/sunderls/HYHZ6/ . Everytime toggling the state, you actually change the class of the element.

    2. if you want it right after the end of text? it's a little tricky, since even if text height is 3 lines, you cannot be sure whether it remains 3 lines height , after appending a button next to it.

      I think one way is to use Range API, to calculate the paragraph dimensions, (I've used the api in my collamark.com, it's powerful but different browsers have different behaviors). Actually you can get the dimensions of every lines dynamically. And by some backwards loops, you can get the appropriate substring of the text, to show in collapsed mode, which is just right for 3 lines height with a button. (the api doc is here: https://developer.mozilla.org/en-US/docs/Web/API/range)

      So now every time you toggle the state, you actually is change the text. not the class.

    Here begins the Code when do it in Angular

    template

    first, this kind of feature is a standalone module which you can reuse everywhere, so in your template, we create a new directive autoFolded, sth like this:

    
        

    Some text here, maybe long maybe short

    directive.coffee

    then we handle all the logic in directive definition( sorry for writing in coffee though)

    directive('autoFolded',[
     '$window'
    ($window) ->
        return {
            restrict: 'E'
            transclude: true
            template: '
    ' link: (scope, element, attrs)-> $$window = $ $window content = $(element).find('.auto-folded') toggleFoldedState = -> if content.hasClass 'auto-folded--folded' content.removeClass('auto-folded--folded').addClass('auto-folded--unfolded') else if content.hasClass 'auto-folded--unfolded' content.removeClass('auto-folded--unfolded').addClass('auto-folded--folded') return scope.toggleFoldedState = toggleFoldedState init = ()-> contentHeight = content.outerHeight() if contentHeight > 48 content.addClass 'auto-folded--folded' content.show() $$window.on 'ngcontentloaded',init } ])

    here is the explaination

    for this directive contains text it doesn't know, so it's a translucent direcitve. Like a modal popup, it contains the Text and a toggle button.

    restrict: 'E'
    transclude: true
    template: '
    '

    when clicking the button, it actually do the toggling. If unfolded, then fold it; If foled, then unfolded. We accomplish this by toggling the classNames, the cold is straightforward

                toggleFoldedState = ->
                    content.css 'color','red'
    
                    if content.hasClass 'auto-folded--folded'
                        content.removeClass('auto-folded--folded').addClass('auto-folded--unfolded')
                    else if content.hasClass 'auto-folded--unfolded'
                        content.removeClass('auto-folded--unfolded').addClass('auto-folded--folded')
    
                    return
    

    and we use ng-click="toggleFoldedState()" to bind this action to the toggling button

    We have to do some initial work to fold the text if it's tall enough at page loaded. However, link function of directive is to create the actual Dom, before dom rendering.So in link, we cannot know the height, that's why we register the init() to ngcontentloaded event:

                init = ()->
                    contentHeight = content.outerHeight()
                    if contentHeight > 48
                        content.addClass 'auto-folded--folded'
                    content.show()
    
                $$window.on 'ngcontentloaded',init
    

    here I use 48px as 3-line-height, you can define your own, or calculate dynamically from the dom, like content.css('lineHeight').

    since this is done after dom rendering, so the text is already displayed before init(). There will be a ugly slideUp effect. That's why we first hide the dom using css(as following), and content.show() in init

    So we are done with directive, the folded/unfoled state are controlled by className. here we go.

    css.sass

    (sorry I wrote it in sass)

    .auto-folded
        display: none  //only display after init()
        position: relative
    
        .auto-folded--more //the button is placed at right-bottom, and default to hidden
            display: none
            position: absolute
            right: 0
            bottom: 0
    
        &.auto-folded--folded //when folded, set maxHeight, and overflow to hidden
            max-height: 48px
            overflow: hidden
            .auto-folded--more // toggling button is displayed,
                display: block
                &:before // and it's text is "more"
                    content: "more"
    
        &.auto-folded--unfolded //when unfoled, s
            .auto-folded--more  // toggling button is displayed
                display: block
                &:before // and it's text is "hide"
                    content: "hide" 
    

    So the text of toggling button and visibility of it , are all controlled by the class of its parent.

    for the parent 1. if text is not 3-line height, it will only have 'auto-folded' as css class, so the button is hidden

    1. if text is over 3-line height, in init() process, it's classNames will be 'auto-folded auto-folded--folded'.
      then the button is shown. clicking it will toggle parent's classNames between 'auto-folded--folded' and 'auto-folded--unfolded'

提交回复
热议问题