如果文字不合适,则显示更多/更少

时间:2018-07-18 07:43:49

标签: javascript jquery

我正在使用jquery创建一些具有动态数据的卡片。有一个描述属性,该属性要么适合卡,要么不适合卡。当它不合适时,我想使卡的大小与其他卡相同,但要添加一个“显示更多/更少”按钮,以扩展卡以显示其余说明。

我创建了一个fiddle,其中显示了卡片的创建以及到目前为止我已经尝试过的操作。

这时我有一个函数checkTruncation,它将检查文本是否适合其容器。这个问题似乎取决于一个事实,即元素尚未渲染,因此元素的宽度为0,这使得函数始终返回true。

功能如下:

let checkTruncation = function (jqueryElement) {
    var $element = jqueryElement;
    if ($element) {
        var $c = $element
            .clone()
            .css({ display: 'inline', width: 'auto', visibility: 'hidden' })
            .appendTo('body');

        let truncated = $c.width() > $element.width()
        console.log($c.width(), $element.width(), $c.width() > $element.width())
        $c.remove();

        return truncated;
    }
    return false;
}

此外,没有建议我重新设计轮子,是否有任何建议的图书馆可以实现此功能?我知道我已经看到过这种行为,但不记得在哪里。

更新

在上面的小提琴中,我只是调用getCard函数,该函数负责提供卡的模板,两次只是为了显示一些示例。在现实生活中,当用户单击按钮时,我通过ajax获取数据并使用以下命令填充卡:

$('.fetchButton').on('click', function(){
    $.get(url, filter)
        .done(function (data) {
            jQuery.each(data, function (index, item) {
                $('.container').append(getCard(item));
            })
        }
})

更新2

@LGSon 的帮助下,我来到了这个scenario,它主要是使用CSS来实现我所需要的。给出的答案仍然有效,并且确实解决了我的问题,因此我将其保留为答案。

2 个答案:

答案 0 :(得分:2)

除了给出了解释原始代码为何无效的答案外,这是另一种方法,显示了如何使用CSS来显示/隐藏“阅读更多...” 按钮

使用absolute: positionoverflow: hidden,我们可以隐藏 “按钮” “文本” 的底部>元素,并且当该元素达到“包装器” 的高度时,隐藏的“ button” 变为可见。

我还利用伪元素和data-*属性将“按钮文本” 保留在标记中,并使用CSS attr()在显示/隐藏时进行切换文字。

堆栈片段

document.querySelectorAll('.readmore').forEach( function(link) {
  link.addEventListener('click', function() {
    this.closest('.wrapper').classList.toggle('show');
  });
});
.wrapper {
  height: 70px;
  border: 1px solid gray;
  overflow: hidden;
}
.wrapper.show {
  height: auto;
}

.text {
  position: relative;
  overflow: hidden;
}

.readmore {
  position: absolute;
  width: 100%;
  top: 52px;
  left: 0;
  background: white;
  color: red;
  cursor: pointer;
}
  .readmore::before {
    content: attr(data-more)
  }
  .wrapper.show .readmore {
    position: relative;
    top: auto;
    display: block;
  }
  .wrapper.show .readmore::before {
    content: attr(data-less)
  }
<div class="wrapper">
  <div class="text">
    Some smaller dummy text here

    <span class="readmore" data-more="Show more..." data-less="Show less..."></span>
  </div>
</div>

<div class="wrapper">
  <div class="text">
    Some bigger dummy text here <br>
    Some bigger dummy text here <br>
    Some bigger dummy text here <br>
    Some bigger dummy text here <br>
    Some bigger dummy text here <br>
    
    <span class="readmore" data-more="Show more..." data-less="Show less..."></span>
  </div>
</div>


如果可能的话,当然可以在CSS中设置“显示更多/更少...” 文本,以简化维护并将其放在一个位置。

document.querySelectorAll('.readmore').forEach( function(link) {
  link.addEventListener('click', function() {
    this.closest('.wrapper').classList.toggle('show');
  });
});
.wrapper {
  height: 70px;
  border: 1px solid gray;
  overflow: hidden;
}
.wrapper.show {
  height: auto;
}

.text {
  position: relative;
  overflow: hidden;
}

.readmore {
  position: absolute;
  width: 100%;
  top: 52px;
  left: 0;
  background: white;
  color: red;
  cursor: pointer;
}
  .readmore::before {
    content: 'Show more...'
  }
  .wrapper.show .readmore {
    position: relative;
    top: auto;
    display: block;
  }
  .wrapper.show .readmore::before {
    content: 'Show less...'
  }
<div class="wrapper">
  <div class="text">
    Some smaller dummy text here

    <span class="readmore"></span>
  </div>
</div>

<div class="wrapper">
  <div class="text">
    Some bigger dummy text here <br>
    Some bigger dummy text here <br>
    Some bigger dummy text here <br>
    Some bigger dummy text here <br>
    Some bigger dummy text here <br>
    
    <span class="readmore"></span>
  </div>
</div>


根据评论进行了更新

这是您的Fiddle / Codepen样本的Stack片段的更新版本

let getCard = function(options) {
  let item = options.data;
  let $parent = options.parent;

  let outerDiv = $('<div>').addClass('shops-content-right');
  let boxDiv = $('<div>').addClass('boxes-right row');
  let shopDiv = $('<div>').addClass('one-shop-box col-md-6 offset-md-3');
  let cubeDiv = $('<div>').addClass('cube text-center');

  let wrapperDiv = $('<div>').addClass('wrapper');
  let textDiv = $('<div>').addClass('text');
  let descriptionP = $('<p>').addClass('text-disc').text(item.description);

  let loadMoreP = $('<span>More >').addClass('readmore');

  textDiv.append([descriptionP, loadMoreP]);
  wrapperDiv.append(textDiv);
  cubeDiv
    .append(wrapperDiv);

  shopDiv.append(cubeDiv);
  boxDiv.append(shopDiv);
  outerDiv.append(boxDiv);

  $parent.append(outerDiv);

  loadMoreP.on('click', function() {
    if (wrapperDiv.hasClass('collapsed')) {
      wrapperDiv.removeClass('collapsed');
      loadMoreP.text("More >");
    } else {
      wrapperDiv.addClass('collapsed');
      loadMoreP.text("Less <");
    }
  })

  return outerDiv;
}


$('.fetchButton').on('click', function() {
  getCard({
    data: {
      description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum'
    },
    parent: $('.container'),
    lines: 3
  })
  getCard({
    data: {
      description: 'Lorem ipsum dolor sit amet, consectetur'
    },
    parent: $('.container'),
    lines: 3
  })
})
.row {
  background: #f8f9fa;
  margin-top: 20px;
}

.col {
  border: solid 1px #6c757d;
  padding: 10px;
}

.one-shop-box {
  border: 1px solid;
}

.shops-content-right .one-shop-box .cube p.text-disc {
  font-size: 16px;
  /*height: 50px;*/
  overflow: hidden;
}

.wrapper {
  height: 90px;
  overflow: hidden;
}

.wrapper.collapsed {
  height: auto;
}

.text {
  position: relative;
  overflow: hidden;
}

.readmore {
  position: absolute;
  width: 100%;
  top: 72px;
  left: 0;
  background: white;
  color: red;
}

.wrapper.collapsed .readmore {
  position: relative;
  top: auto;
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<!-- 
  Bootstrap docs: https://getbootstrap.com/docs
-->

<div class="container">
  <button class="fetchButton">
Fetch Data
</button>

</div>

答案 1 :(得分:1)

发生这种情况是因为您没有将元素追加到文档中,因此其宽度为0。因此,请按以下方式更新代码:

let checkTruncation = function($element) {
  if ($element) {
    var $c = $element
      .clone()
      .css({ display: 'inline', width: 'auto', visibility: 'hidden' })
      .appendTo('body');

    let truncated = $c.width() > $element.width();
    // console.log($c.width(), $element.width(), $c.width() > $element.width());
    $c.remove();

    return truncated;
  }
    
  return false;
};

let baseUrl ='';

let getCard = function(item, $parent) {
  let outerDiv = $('<div>').addClass('shops-content-right');
  let boxDiv = $('<div>').addClass('boxes-right row');
  let shopDiv = $('<div>').addClass('one-shop-box col-md-6 offset-md-3');
  let cubeDiv = $('<div>').addClass('cube text-center');
  let descriptionP = $('<p>').addClass('text-disc').text(item.description).addClass('collapsed');
  let loadMoreP = $('<p>').css({ 'font-size': '16px', 'cursor': 'pointer' }).text("More >");

  cubeDiv.append(descriptionP).append(loadMoreP);
  shopDiv.append(cubeDiv);
  boxDiv.append(shopDiv);
  outerDiv.append(boxDiv);
  $parent.append(outerDiv);

  loadMoreP.on('click', function () {
    if (descriptionP.hasClass('collapsed')) {
      descriptionP.removeClass('collapsed');
      loadMoreP.text("Less <");
    } else {
      descriptionP.addClass('collapsed');
      loadMoreP.text("More >");
    }
  });

  if (checkTruncation(descriptionP)) {
    loadMoreP.show();
  } else {
    loadMoreP.hide();
  }
};

const $container = $('.container');

getCard({
  description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum'
}, $container);

getCard({
  description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'
}, $container);
.row {
  background: #f8f9fa;
  margin-top: 20px;
}

.col {
  border: solid 1px #6c757d;
  padding: 10px;
}

.one-shop-box {
  border:1px solid;
}

.shops-content-right .one-shop-box .cube p.text-disc {
  font-size: 16px;
  height: 50px;
  overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<div class="container"></div>

我将容器元素传递给函数getCard(),并在调用函数checkTruncation().之前将新元素附加到其中

并按如下所示更新调用getCard()的代码:

const $container = $('.container');
$('.fetchButton').on('click', function() {
  $.get(url, filter).done(function(data) {
    $.each(data, function(index, item) {
      getCard(item, $container);
    });
  });
});