Эффективная замена строки Javascript - PullRequest
30 голосов
/ 18 декабря 2008

Привет, у меня есть блок HTML, который я собираюсь использовать неоднократно (в разное время во время посещения пользователей, а не сразу). Я думаю, что лучший способ сделать это - создать HTML-div, скрыть его, а при необходимости взять его innerHTML и выполнить replace () для нескольких ключевых слов. В качестве примера HTML-блок ...

<div id='sample'>
  <h4>%TITLE%</h4>
  <p>Text text %KEYWORD% text</p>
  <p>%CONTENT%</p>
  <img src="images/%ID%/1.jpg" />
</div>

Будет ли лучший способ заменить эти ключевые слова динамическими данными?

template = document.getElementById('sample');
template = template.replace(/%TITLE%/, some_var_with_title);
template = template.replace(/%KEYWORD%/, some_var_with_keyword);
template = template.replace(/%CONTENT%/, some_var_with_content);
template = template.replace(/%ID%/, some_var_with_id);

Такое ощущение, что я выбрал глупый способ сделать это. У кого-нибудь есть какие-либо предложения о том, как сделать это быстрее, умнее или лучше? Этот код будет выполняться довольно часто во время посещения пользователя, иногда так часто, как раз в 3-4 секунды.

Заранее спасибо.

Ответы [ 11 ]

80 голосов
/ 18 декабря 2008

Похоже, вы хотите использовать шаблон.

//Updated 28 October 2011: Now allows 0, NaN, false, null and undefined in output. 
function template( templateid, data ){
    return document.getElementById( templateid ).innerHTML
      .replace(
        /%(\w*)%/g, // or /{(\w*)}/g for "{this} instead of %this%"
        function( m, key ){
          return data.hasOwnProperty( key ) ? data[ key ] : "";
        }
      );
}

Пояснение к коду:

  • Ожидается, что templateid будет идентификатором существующего элемента.
  • Ожидается, что data будет объектом с данными.
  • Для замены используются два параметра:
  • Первым является регулярное выражение, которое ищет все %keys% (или {keys}, если вы используете альтернативную версию). Ключ может быть комбинацией A-Z, a-z, 0-9 и подчеркивания _.
  • Вторая - анонимная функция, которая вызывается при каждом совпадении.
  • Анонимная функция ищет в объекте данных ключ, найденный регулярным выражением. Если ключ найден в данных, то возвращается значение ключа, и это значение будет заменять ключ в конечном выводе. Если ключ не найден, возвращается пустая строка.

Пример шаблона:

<div id="mytemplate">
  <p>%test%</p>
  <p>%word%</p>
</div>

Пример звонка:

document.getElementById("my").innerHTML=template("mytemplate",{test:"MYTEST",word:"MYWORD"});
18 голосов
/ 18 декабря 2008

Вы могли бы, вероятно, адаптировать этот код, чтобы делать то, что вы хотите:

var user = {
    "firstName": "John",
    "login": "john_doe",
    "password": "test",
};

var textbody = ""
+"Hey {firstName},\n"
+"\n"
+"You recently requested your password.\n"
+"login: {login}\n"
+"password: {password}\n"
+"\n"
+"If you did not request your password, please disregard this message.\n"
+"";

textbody = textbody.replace(/{[^{}]+}/g, function(key){
    return user[key.replace(/[{}]+/g, "")] || "";
});

Возможно, вы также захотите посмотреть JavaScriptTemplates

12 голосов
/ 18 декабря 2008

Я сомневаюсь, что будет что-то более эффективное. Альтернативой было бы разделить его на части, а затем объединить, но я не думаю, что это будет очень эффективно. Возможно, даже меньше, учитывая, что каждая конкатенация приводит к новой строке, размер которой равен размеру ее операндов.

Добавлено: Это, пожалуй, самый элегантный способ написать это. Кроме того - о чем ты беспокоишься? Использование памяти? Это в изобилии, и у Javascript есть приличный менеджер памяти. Скорость исполнения? Тогда у вас должна быть какая-то гигантская строка. ИМХО это хорошо.

7 голосов
/ 26 мая 2018

Замена шаблона

Быстрое и простое решение - использовать метод String.prototype.replace .
Он принимает второй параметр, который может быть либо значением, либо функцией:

function replaceMe(template, data) {
    const pattern = /\{(.*?)\}/g; // {property}
    return template.replace(pattern, (match, token) => data[token]);
}

Пример :

const html = `
    <div>
        <h4>{title}</h4>
        <p>My name is {name}</p>
        <img src="{url}" />
    </div>
`;

const data = {
    title: 'My Profile',
    name: 'John Smith',
    url: 'http://images/john.jpeg'
};

И назовите это так:

replaceMe(html, data);
1 голос
/ 20 января 2017

При таком подходе создаются шаблоны функций, которые можно кэшировать:

function compileMessage (message) {

  return new Function('obj', 'with(obj){ return \'' +
    message.replace(/\n/g, '\\n').split(/{{([^{}]+)}}/g).map(function (expression, i) {
      return i%2 ? ( '\'+(' + expression.trim() + ')+\'' ) : expression;
    }).join('') + 
  '\'; }');

}

var renderMessage = compileMessage('Hi {{ recipient.first_name }},\n\n' +

'Lorem ipsum dolor sit amet...\n\n' +

'Best Regarts,\n\n' +

'{{ sender.first_name }}');


renderMessage({
  recipient: {
    first_name: 'John'
  },
  sender: {
    first_name: 'William'
  }
});

возвращается:

"Hi John,

Lorem ipsum dolor sit amet...

Best Regarts,

William"
1 голос
/ 18 декабря 2008

Ваш метод является стандартным способом реализации шаблонной системы для бедняков, так что все в порядке.

Может быть стоит попробовать некоторые библиотеки шаблонов JavaScript, такие как JST .

1 голос
/ 18 декабря 2008

Если вы хотите использовать библиотеку прототипов , у них есть хорошая встроенная функциональность шаблонов.

Это будет выглядеть так:

element.innerHTML = (new Template(element.innerHTML)).evaluate({
    title: 'a title',
    keyword: 'some keyword',
    content: 'A bunch of content',
    id: 'id here'
})

Это было бы особенно хорошо, если бы вы выполняли свой код в цикле из-за простоты создания объектов JSON / литералов объектов Javascript.

Тем не менее, я не ожидал бы никакого увеличения скорости.

Кроме того, вам необходимо изменить стиль разделителя на #{keyword} вместо %keyword%

1 голос
/ 18 декабря 2008

Вы можете сделать его более эффективным, цепочкой замен вместо выполнения всех этих временных назначений.

т.е.

with(document.getElementById('sample'))
{
  innerHTML = innerHTML.replace(a, A).replace(b, B).replace(c, C); //etc
}
0 голосов
/ 04 августа 2016

Попробуйте это: http://json2html.com/

Он также поддерживает сложные объекты JSON.

0 голосов
/ 15 октября 2015
var template = "<div id='sample'><h4>%VAR%</h4><p>Text text %VAR% text</p><p>%VAR%</p><img src="images/%VAR%/1.jpg" /></div>";

var replace = function(temp,replace){
temp = temp.split('%VAR%');
for(var i in replace){
          if(typeof temp[i] != 'undefined'){
            temp[i] = temp[i] + replace[i];
          }
        }
   return temp.join('');
}

replace(template,['title','keyword','content','id'])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...