Подтвердить что ты не робот

Плавно меняя текст с помощью JavaScript

Я делаю целевую страницу, где фраза постоянно меняется с помощью выбранных слов. Например,

Дизайн лучших сайтов
для клиентов.

будет переключать первое или последнее слово, чтобы стать

Разработка лучших веб-сайтов
для клиентов.

Однако, поскольку "Разработка" - это более крупное слово, чем "Дизайн", остальная часть текста заканчивается тем, что происходит без плавного перехода. Имейте в виду, это многострочное предложение, и оно сосредоточено.

var first  = ['Create','Design','Develop'];
var second = ['you','clients','artists','us'];
var i = 0;
var j = 0;
var maxfirst  = first.length - 1;
var maxsecond = second.length - 1;

function delay() {
    $('#intro').velocity("transi1ion.slideUpIn", 1250);
    setInterval(firstwordchange, 400);
    setInterval(secondwordchange, 500);
}

function firstwordchange() {
    if (i < maxfirst) i++; else i = 0;

    $('#firstword').velocity("transition.slideUpOut", 300);

    setTimeout(function () {
        $('#firstword').text(first[i]);
    }, 200);

  $('#firstword').velocity("transition.slideUpIn", 300);
}

function secondwordchange() {
    if (j < maxsecond) j++; else j = 0;

    $('#secondword').velocity("transition.slideUpOut", 300);

    setTimeout(function () {
        $('#secondword').text(second[j]);
    }, 200);

    $('#secondword').velocity("transition.slideUpIn", 300);
}

setTimeout(delay, 700);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/velocity/1.1.0/velocity.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/velocity/1.1.0/velocity.ui.min.js"></script>
<div id="intro">
    <span id="firstword" class="introchange">Create</span>
    better websites made for
    <span id="secondword" class="introchange">you</span>.
</div>
4b9b3361

Ответ 1

Я собираюсь написать схему, как это сделал < :

  • Отметьте предложение, используя начальные значения по умолчанию для меняющихся слов и статического позиционирования.
  • Также отобразите другие варианты слов с помощью visibility: hidden, чтобы вы могли определить их размеры.
  • Абсолютизировать каждую часть предложения. С этого момента все будет абсолютно позиционировано, поэтому лучше всего, если у вас есть хороший контекст позиционирования вокруг него (обычно это делается с position: relative на родительском объекте).
  • Измерьте каждую часть предложения, как изменяя слова, так и фиксированные ширины частей предложения, включая скрытые.
  • При изменении слов вычисляются различия между старыми размерами и новыми. Исходя из этих различий, используйте очень простую математику, чтобы увидеть, сколько частей должно перемещаться влево или вправо и применять к ним горизонтальный перевод (и, конечно, оживить перевод - возможно, только для того, что вы хотите перемещать влево/вправо, возможно, вы хотите другой эффекты для меняющихся слов).

Demo:

var first = ['Create','Cut','Reticulate'];
var second = ['you','clients','artists','us'];
var firstM = [], secondM = [], el;

var $first = $('.the-first'); 
var $second = $('.the-second'); 
var $container = $('#container');

// init static //    
$first.text(first[0]);
$second.text(second[0]);

// create measurables //
for(var i = 0; i < first.length; i++){
    el = $('<div class="measurable">' + first[i] + '</div>');
    $container.append(el);
    firstM.push(el.width());
}
for(var i = 0; i < second.length; i++){
    el = $('<div class="measurable">' + second[i] + '</div>');
    $container.append(el);
    secondM.push(el.width());
}

// absolutize //
var positions = [];
$('#container > span').each(function(){
    positions.push($(this).position());
});
$('#container > span').each(function(){
    var pos = positions.shift();
    $(this).css({
        position: 'absolute',
        left: pos.left,
        top: pos.top
    });
});

// remember initial sizes //
var firstInitialWidth = $first.width();
var secondInitialWidth = $second.width();

// loop the loop //
var activeWordsIndex = 0;
setInterval(function(){
    activeWordsIndex++;
    var firstIndex = activeWordsIndex % first.length;
    var secondIndex = activeWordsIndex % second.length;
    
    $first.text( first[firstIndex] );
    $second.text( second[secondIndex] );
    
    var firstLineOffset = (firstM[firstIndex] - firstInitialWidth) / 2;
    var secondLineOffset = (secondM[secondIndex] - secondInitialWidth) / 2;
   
    $('.static.first').css({
        transform: 'translateX(' + firstLineOffset + 'px)'
    });
    $('.static.second').css({
        transform: 'translateX(' + (-secondLineOffset) + 'px)'
    });
    
    $first.css({
        transition: 'none', 
        transform: 'translate(' + (-firstLineOffset) + 'px, -30px)',
        opacity: '0'
    });
    setTimeout(function(){
        $first.css({
            transition: 'all 1s ease',
            transform: 'translate(' + (-firstLineOffset) + 'px, 0px)',
            opacity: '1'
        });
    }, 50);
    
    $second.css({
        transition: 'none', 
        transform: 'translate(' + (-secondLineOffset) + 'px, 30px)',
        opacity: '0'
    });
    setTimeout(function(){
        $second.css({
            transition: 'all 1s ease',
            transform: 'translate(' + (-secondLineOffset) + 'px, 0px)',
            opacity: '1'
        });
    }, 50);
}, 2000);
#ubercontainer {
    border: 1px solid #eaeaea;
    border-radius: 2px;
    background-color: #ffefc6;
    width: 500px;
    margin: 20px auto;
    padding: 30px 0;
}
#container {
    position: relative;
    text-align: center;
    font-family: sans-serif;
    font-size: 32px;
    font-weight: 800;
    color: #4a6b82;
    height: 78px;
}
.measurable {
    position: absolute;
    visibility: hidden;
}

.static.first, .static.second {
    transition: transform 1s ease;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="ubercontainer">
<div id="container">
    <span class="the-first"></span> 
    <span class="static first">better websites </span><br />
    <span class="static second">made for</span> 
    <span class="the-second"></span>
</div>
</div>

Ответ 2

Написав такое решение, вы быстро поймете, что вам придется отказаться от идеи динамических разрывов строк, если ваши слова различаются по длине на разумную сумму.

Эта небольшая деталь в стороне, вы можете легко достичь эффекта, который вы используете, используя стандартную пирамиду jQuery animate callback hell:

var target = $('#target');
var change = function(str) {
  var tmp = $('<h1>' + str + '</h1>');
  tmp.css({
      display: "inline-block",
      position: "absolute"
    })
    .appendTo('body')
    .hide();
  var targetWidth = tmp.outerWidth();
  tmp.remove();
  target.animate({
    opacity: 0
  }, 200, function() {
    target.animate({
      width: targetWidth
    }, 300, function() {
      target.empty()
        .html(str)
        .css({
          display: "initial"
        })
        .animate({
          opacity: 1
        }, 200);
    });
  });
}
var samples = [
  "some sample",
  "another example",
  "just"
];
var i = 0;
setInterval(function() {
  change(samples[++i % samples.length]);
}, 1400);
.container {
  margin: 0 auto;
  text-align: center;
}
#target {
  display: inline-block;
  vertical-align: bottom;
  white-space: no-wrap;
  height: 1em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <h1>This is <span id="target"></span> text</h1>
  <h1>in a longer sentence</h1>
</div>

Ответ 4

Получил хорошие ответы.
У Алина Пуркару есть намного лучший и более согласованный ответ, но я думал, что предоставил бы свой.

У Нита было то, что я искал, но поскольку я не лучший программист, я попытался найти решение, которое я мог бы понять. Через час или два, вот что я получил.

В принципе, я сравниваю полный блок текста с родительским элементом, нахожу пространство между ними, уменьшая его пополам, а затем применяя это как отрицательное поле к тексту. Я могу перейти с помощью CSS, так как я перемещаю полный блок.

Здесь очень плохой рисунок в MSpaint, чтобы проиллюстрировать мою точку

enter image description here

текст имеет display: inline-block, поэтому div подходит для текста, а не занимает 100% родительского.

Поскольку я был переход с CSS в свой javascript, все, что мне нужно было сделать, чтобы сделать его гладким, было

  -webkit-transition: all 1s ease-in-out;
  -moz-transition: all 1s ease-in-out;
  -o-transition: all 1s ease-in-out;
  transition: all 1s ease-in-out;