ES6 şablon değişmez değerleri çalışma zamanında değiştirilebilir (veya yeniden kullanılabilir)?


129

tl; dr: Yeniden kullanılabilir bir şablonu değişmez yapmak mümkün müdür?

Şablon değişmezlerini kullanmaya çalışıyordum ama sanırım anlamıyorum ve şimdi sinirleniyorum. Demek istediğim, anladığımı düşünüyorum, ama "o" nasıl çalıştığı veya nasıl olması gerektiği olmamalı. Farklı şekilde olmalı.

Gördüğüm tüm örnekler (etiketli şablonlar bile) "ikamelerin" bildirim zamanında yapılmasını ve çalışma zamanında yapılmamasını gerektiriyor, ki bu bana bir şablon için tamamen yararsız geliyor. Belki deliyim, ama benim için "şablon", onu yarattığınızda değil, kullandığınızda değiştirilen belirteçleri içeren bir belgedir, aksi takdirde sadece bir belgedir (yani bir dizedir). Bir şablon, jeton olarak jetonlarla birlikte saklanır ve bu jetonlar, siz onu değerlendirdiğinizde değerlendirilir.

Herkes şuna benzer korkunç bir örnek veriyor:

var a = 'asd';
return `Worthless ${a}!`

Bu güzel, ama zaten biliyorsam a, sadece return 'Worthless asd'ya da yapardım return 'Worthless '+a. Amaç ne? Ciddi anlamda. Tamam mesele tembellik; daha az artı, daha fazla okunabilirlik. Harika. Ama bu bir şablon değil! IMHO değil. Ve MHO önemli olan tek şey! Sorun, IMHO, şablonun ilan edildiğinde değerlendirilmesidir, bu nedenle, eğer yaparsanız, IMHO:

var tpl = `My ${expletive} template`;
function go() { return tpl; }
go(); // SPACE-TIME ENDS!

Yana expletivebildirilmedi, şöyle birşeyler verir My undefined template. Süper. Aslında, en azından Chrome'da şablonu beyan edemiyorum; expletivetanımlı olmadığı için bir hata atar . İhtiyacım olan şey, şablonu beyan ettikten sonra değişikliği yapabilmektir:

var tpl = `My ${expletive} template`;
function go() { return tpl; }
var expletive = 'great';
go(); // My great template

Ancak bunun nasıl mümkün olduğunu anlamıyorum çünkü bunlar gerçekten şablonlar değil. Etiketleri kullanmam gerektiğini söyleseniz bile, hayır, işe yaramıyorlar:

> explete = function(a,b) { console.log(a); console.log(b); }
< function (a,b) { console.log(a); console.log(b); }
> var tpl = explete`My ${expletive} template`
< VM2323:2 Uncaught ReferenceError: expletive is not defined...

Tüm bunlar beni şablon değişmezlerinin korkunç bir şekilde yanlış adlandırıldığına ve gerçekte oldukları gibi adlandırılmaları gerektiğine inandırdı: heredoc . Sanırım "literal" kısmı beni uyarmalıydı (olduğu gibi, değişmez)?

Bir şey mi kaçırıyorum? Yeniden kullanılabilir bir şablonu değişmez hale getirmenin (iyi) bir yolu var mı?


Size yeniden kullanılabilir şablon değişmezlerini veriyorum :

> function out(t) { console.log(eval(t)); }
  var template = `\`This is
  my \${expletive} reusable
  template!\``;
  out(template);
  var expletive = 'curious';
  out(template);
  var expletive = 'AMAZING';
  out(template);
< This is
  my undefined reusable
  template!
  This is
  my curious reusable
  template!
  This is
  my AMAZING reusable
  template!

Ve işte saf bir "yardımcı" işlevi ...

function t(t) { return '`'+t.replace('{','${')+'`'; }
var template = t(`This is
my {expletive} reusable
template!`);

...daha iyi yapmak için".

Kıvrımlı hisler ürettikleri alan nedeniyle onlara şablon guterals demeye meyilliyim.


1
Üstünü çizmeyi destekliyor (ancak bu gibi yorumlarda değil). Metninizi bir <strike>etikete koyun .
Pointy

ES6 şablon değişmez değerleri çoğunlukla eski moda String enterpolasyonu içindir. Dinamik şablonlar istiyorsanız, Gidon vb. Veya Pointy'nin etiketli şablon çözümünü kullanın.
joews

1
Şablon dizeleri isme rağmen şablon değildir . Ayrıca bkz . ES6 Şablon Dizeleri için yürütmeyi ertele
Bergi

8
Lütfen gönderinizi biraz daha az gürültülü hale getirir misiniz? Eğer böyle yaparsa, "lütfen kaldırın, Q & A biçiminde bir öğretici yazmak için amaçlanan gibi Ayrıca, görünüşe sizlere ... senin dan" bölümünü sorusuna ve bir cevap olarak yayınlamayın .
Bergi

Burada pek çok güzel cevap olduğunu fark ettim. Belki birini kabul edin.
abalter

Yanıtlar:


86

Bu değişmez değerlerin diğer şablon motorları gibi çalışmasını sağlamak için bir ara form olması gerekir.

Bunu yapmanın en iyi yolu yapıcıyı kullanmaktır Function.

const templateString = "Hello ${this.name}!";
const templateVars = {
    name: "world"    
}

const fillTemplate = function(templateString, templateVars){
    return new Function("return `"+templateString +"`;").call(templateVars);
}

console.log(fillTemplate(templateString, templateVars));

Diğer şablon motorlarında olduğu gibi, bu dizeyi bir dosya gibi başka yerlerden de alabilirsiniz.

Bu yöntemi kullanırken, şablon etiketlerinin kullanımının zor olması gibi sorunlar olabilir, ancak zekiyseniz bunlar eklenebilir. Ayrıca geç enterpolasyon nedeniyle satır içi JavaScript mantığına sahip olamazsınız. Bu, biraz düşünülerek de düzeltilebilir.


8
Güzel! Hatta kullanabilirsiniznew Function(`return \`${template}\`;`)
Ruben Stolk

Ve bu şablonlar oluşturulabilir veya bir yöntemi çağırarak veya başka bir şablonun derlenmiş sonucunu ileterek argümanlar aracılığıyla "dahil edilebilir".
Quentin Engles

Quentin 'şablon etiketi yok' ne anlama geliyor? Teşekkürler!
mikemaccana

10
dikkat bu şablon dizesi biraz öyle bir şey haline DEĞİL transpile böylece edecek transpilation için 'gizli' (yani webpack) ve (yani IE11) yeterince uyumlu istemci tarafında ...!
Frank Nocke

9
XSS güvenlik açığı ? Ayrıntılar BU JSFIDDLE
Kamil Kiełczewski

65

Bir işleve bir şablon dizesi koyabilirsiniz:

function reusable(a, b) {
  return `a is ${a} and b is ${b}`;
}

Aynı şeyi etiketli bir şablonla da yapabilirsiniz:

function reusable(strings) {
  return function(... vals) {
    return strings.map(function(s, i) {
      return `${s}${vals[i] || ""}`;
    }).join("");
  };
}

var tagged = reusable`a is ${0} and b is ${1}`; // dummy "parameters"
console.log(tagged("hello", "world"));
// prints "a is hello b is world"
console.log(tagged("mars", "jupiter"));
// prints "a is mars b is jupiter"

Buradaki fikir, şablon ayrıştırıcının sabit dizeleri "yuvalar" değişkeninden ayırmasına izin vermek ve ardından her seferinde yeni bir değer kümesine dayalı olarak hepsini bir araya getiren bir işlev döndürmektir.


3
@FelixKling olabilir; Kontrol edip düzelteceğim eğer öyleyse. düzenle evet, örneğin "yeniden kullanılabilir" işlev olan önemli bir bölümünü dışarıda bırakmışım gibi görünüyor :)
Pointy

@FelixKling Ne yapacağımı bilmiyorum çünkü o sırada ne düşündüğümü hiç hatırlayamıyorum!
Sivri

1
Her zaman kaldırabilirsiniz .... ama); Evet, tbh ya olmak çok mantıklı değil reusablebu yüzden bir işlevi döndüren uygulamak mümkündür ve kullanmak istiyorum ${0}ve ${1}yerine edebi iç ${a}ve ${b}. Ardından, Bergi'nin son örneğinde yaptığı gibi, işlevin argümanlarına başvurmak için bu değerleri kullanabilirsiniz: stackoverflow.com/a/22619256/218196 (veya temelde aynı olduğunu tahmin ediyorum).
Felix Kling

1
@FelixKling Tamam Sanırım, OP'nin çizgisinde en azından belli belirsiz olan bir şey buldum.
Sivri

3
Sonuç aslında bir dize değilse, etiketli şablonlar gerçekten güçlü olabilir. Örneğin, projelerimden birinde AST düğüm enterpolasyonu yapmak için kullanıyorum. Örneğin expression`a + ${node}`, mevcut bir AST düğümü ile bir BinaryExpression düğümü oluşturmak yapılabilir node. Dahili olarak, geçerli bir kod oluşturmak için bir yer tutucu ekleriz, bunu bir AST olarak ayrıştırırız ve yer tutucuyu geçirilen değerle değiştiririz.
Felix Kling

45

Muhtemelen bunu yapmanın en temiz yolu ok işlevleridir (çünkü bu noktada zaten ES6 kullanıyoruz)

var reusable = () => `This ${object} was created by ${creator}`;

var object = "template string", creator = "a function";
console.log (reusable()); // "This template string was created by a function"

object = "example", creator = "me";
console.log (reusable()); // "This example was created by me"

... Ve etiketli şablon değişmez değerleri için:

reusable = () => myTag`The ${noun} go ${verb} and `;

var noun = "wheels on the bus", verb = "round";
var myTag = function (strings, noun, verb) {
    return strings[0] + noun + strings[1] + verb + strings[2] + verb;
};
console.log (reusable()); // "The wheels on the bus go round and round"

noun = "racecars", verb = "fast";
myTag = function (strings, noun, verb) {
    return strings[0] + noun + strings[1] + verb;
};
console.log (reusable()); // "The racecars go fast"

Bu aynı zamanda kullanılmasını önler eval()veya Function()derleyici sorunlara neden ve yavaşlamanın bir çok neden olabilir.


Bence bu en iyisi çünkü myTagbazı şeyler yapmak için fonksiyonun içine bazı kodları enjekte edebilirsiniz . Örneğin, çıktıyı önbelleğe almak için anahtar olarak giriş parametrelerini kullanın.
WOW

Bunun en iyi cevap olduğunu düşünüyorum. Ayrıca ben bile daha temiz hale getirir düşünmek ok işlevine parametreleri ekleyebilirsiniz: var reusable = (value: string) => `Value is ${value}`.
haggisandchips

13

2019 yanıtı :

Not : Kitaplık başlangıçta kullanıcıların XSS'den kaçınmak için dizeleri temizlemesini bekliyordu. Kütüphanenin 2. Versiyonu artık tamamen ortadan kalktığı için kullanıcı dizilerinin (web geliştiricilerinin yine de yapması gereken) sterilize edilmesini gerektirmiyor eval.

es6-dynamic-templateNPM üzerinde modül yapar.

const fillTemplate = require('es6-dynamic-template');

Mevcut cevapların aksine:

  • Benzer bir format değil, ES6 şablon dizelerini kullanır. Güncelleme sürümü 2, kullanıcıların temizlenmemiş giriş Dizelerini kullanmasını önlemek için ES6 şablon dizeleri yerine benzer bir biçim kullanır.
  • thisŞablon dizesine ihtiyaç duymaz
  • Şablon dizesini ve değişkenlerini tek bir işlevde belirtebilirsiniz
  • StackOverflow'dan kopyalamak yerine, korunan, güncellenebilir bir modüldür

Kullanımı basittir. Şablon dizisi daha sonra çözüleceği için tek tırnak kullanın!

const greeting = fillTemplate('Hi ${firstName}', {firstName: 'Joe'});

Bunu React Native ile kullanıyorsanız, Android'de özel olarak kırılacaktır. Android düğüm çalışma zamanı dinamik şablonları desteklemiyor, yalnızca önceden doldurulmuş şablonları desteklemiyor
Oliver Dixon,

1
Bu kişisel projelerimde kullandığım bir çözüm ve kusursuz çalışıyor. Aslında, özellikle bunun gibi küçük araçlar için çok fazla kitaplık kullanmanın kötü bir fikir olduğunu düşünüyorum.
Oliver Dixon

1
XSS güvenlik açığı ? Ayrıntılar BU FIDDLE
Kamil Kiełczewski

1
@kamil Yalnızca XSS, a) kullanıcılara oluşturma yeteneği verirseniz b) giriş dizelerini temizlemeyin. Yine de insanların kullanıcı girdilerini temizlemesi gerektiğine dair bir uyarı ekleyeceğim.
mikemaccana

1
Bu, es6 şablon değişmezlerini uzaktan kullanmaz. Deneyin 10 * 20 = ${10 * 20}öyleyse, benzer bir format olabilir, ancak uzaktan bile es6 şablon değişmezleri değil
gman

12

Evet, dizenizi şablonla JS olarak ayrıştırarak Function(veya eval) yapabilirsiniz - ancak bu önerilmez ve XSS saldırısına izin verir

Bunun yerine, nesne alanlarını şablona aşağıdaki gibi dinamik bir şekilde güvenle ekleyebilirsiniz.objstr

let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);


Kullandığım yöntem bu ve iyi çalıştı. İyi örnek! Mı? RegEx yardımındaki * işaretinden sonra? RegEx uzmanı değilim, ama tahminimce * sıfır veya daha fazla anlamına geldiğinden (ve bu durumda "daha fazlasını" istiyorsunuz), açgözlü kısıtlamaya gerek yok mu?
Gen1-1

@ Gen1-1, açgözlü olmayan.*? anlamına gelir - kaldırırsanız pasaj yanlış sonuç verir"?"
Kamil Kiełczewski

Haklısın benim hatam. Şablonlarımda $ kullanmıyorum ve RegEx: / {(\ w *)} / g kullanıyorum çünkü etikette hiçbir zaman boşluk yok, ama. *? ayrıca çalışır. function taggedTemplate(template, data, matcher) { if (!template || !data) { return template; } matcher = matcher || /{(\w*)}/g; // {one or more alphanumeric characters with no spaces} return template.replace(matcher, function (match, key) { var value; try { value = data[key] } catch (e) { // } return value || ""; }); }
Kullanıyorum

@ Gen1-1 iç içe geçmiş veriler de var mı? gibi data = { a: 1, b: { c:2, d:3 } }-> b.c?
muescha

1
@muescha Özyinelemeyi kullanmak ve özelliği bulana kadar tüm veri nesnenizi ve iç içe nesnelerinizi aramak için line: value = data [key] 'i değiştirirsiniz. Örnekler: codereview.stackexchange.com/questions/73714/… ve mikedoesweb.com/2016/es6-depth-first-object-tree-search
Gen1-1

9

@Metamorphasi tarafından sağlanan cevabı basitleştirmek;

const fillTemplate = function(templateString, templateVars){
  var func = new Function(...Object.keys(templateVars),  "return `"+templateString +"`;")
  return func(...Object.values(templateVars));
}

// Sample
var hosting = "overview/id/d:${Id}";
var domain = {Id:1234, User:22};
var result = fillTemplate(hosting, domain);

console.log(result);


Bu kod, önde gelen cevaptan daha kendini açıklar.
Oyumu aldım

Bu, değişkenleri veya harici dosyaları (NodeJS'de) şablon olarak kullanmanıza veya çalışma zamanında dinamik olarak oluşturmanıza izin vermelidir. Kullanmadan eval.
b01

XSS güvenlik açığı ? BURADA kötü niyetli kod (değişken var hosting) ile oynayın .
Kamil Kiełczewski

7

Eğer şablonda, değişkenleri başvurmak sipariş parametreleri veya bağlam / ad alanları kullanmak istemiyorsanız örneğin ${0}, ${this.something}ya da ${data.something}, sizin için kapsama alınması ilgilenir bir şablon işlevi olabilir.

Örnek Eğer böyle bir şablon diyebiliriz nasıl:

const tempGreet = Template(() => `
  <span>Hello, ${name}!</span>
`);
tempGreet({name: 'Brian'}); // returns "<span>Hello, Brian!</span>"

Şablon işlevi:

function Template(cb) {
  return function(data) {
    const dataKeys = [];
    const dataVals = [];
    for (let key in data) {
      dataKeys.push(key);
      dataVals.push(data[key]);
    }
    let func = new Function(...dataKeys, 'return (' + cb + ')();');
    return func(...dataVals);
  }
}

Bu durumda ilginç olan, ES6 şablonunun değişmez değerini döndüren bir işlevi (örnekte bir ok işlevi kullandım) geçirmeniz gerektiğidir. Bence peşinde olduğumuz türden yeniden kullanılabilir enterpolasyonu elde etmek küçük bir değiş tokuş.

İşte GitHub'da: https://github.com/Adelphos/ES6-Reuseable-Template


3
Bu iyi, ama küçültülmesi (vals, fonk, vs) unnecessaery olduğunu 'cb' bir geri arama (bu tamamen senkron kodudur) değildir ve sadece kullanabilirsiniz Object.values()veObject.keys()
mikemaccana

3

Kısa cevap, lodash'ta _.template kullanmaktır .

// Use the ES template literal delimiter as an "interpolate" delimiter.
// Disable support by replacing the "interpolate" delimiter.
var compiled = _.template('hello ${ user }!');
compiled({ 'user': 'pebbles' });
// => 'hello pebbles!'

3

Bir şey mi kaçırıyorum? Yeniden kullanılabilir bir şablonu değişmez hale getirmenin [iyi] bir yolu var mı?

Belki bir şeyi kaçırıyorum, çünkü bu konudaki çözümüm bana o kadar açık geliyor ki, kimsenin bu kadar eski bir soruda bunu yazmamış olmasına çok şaşırdım.

Bunun için neredeyse tek bir satırım var:

function defer([first, ...rest]) {
  return (...values) => rest.reduce((acc, str, i) => acc + values[i] + str, first);
}

Bu kadar. Bir şablonu yeniden kullanmak ve ikamelerin çözümünü ertelemek istediğimde, sadece şunu yapıyorum:

> t = defer`My template is: ${null} and ${null}`;
> t('simple', 'reusable');          // 'My template is: simple and reusable'
> t('obvious', 'late to the party'; // 'My template is: obvious and late to the party'
> t(null);                          // 'My template is: null and undefined'
>
> defer`Choose: ${'ignore'} / ${undefined}`(true, false); // 'Choose: true / false'

Bu etiketin uygulanması , değişmez değere geçirilen parametreleri yok sayan a 'function'(a yerine 'string') döndürür . Daha sonra yeni parametrelerle daha sonra çağrılabilir. Bir parametrenin karşılık gelen değişimi yoksa, olur 'undefined'.


Genişletilmiş cevap

Bu basit kod işlevseldir, ancak daha ayrıntılı davranışa ihtiyacınız varsa, aynı mantık uygulanabilir ve sonsuz olasılıklar vardır. Yapabilirdiniz:

  1. Orijinal parametreleri kullanın:

Yapıda değişmez değere aktarılan orijinal değerleri saklayabilir ve şablonu uygularken bunları yaratıcı şekillerde kullanabilirsiniz. İşaretler, tip doğrulayıcılar, işlevler vb. Haline gelebilirler. Bu, onları varsayılan değerler olarak kullanan bir örnektir:

    function deferWithDefaults([first, ...rest], ...defaults) {
      return (...values) => rest.reduce((acc, curr, i) => {
        return acc + (i < values.length ? values[i] : defaults[i]) + curr;
      }, first);
    }

Sonra:

    > t = deferWithDefaults`My template is: ${'extendable'} and ${'versatile'}`;
    > t('awesome');                 // 'My template is: awesome and versatile' 
  1. Bir şablon fabrikası yazın:

Bu mantığı, bağımsız değişken olarak, indirgemede uygulanabilen (şablon değişmezinin parçalarını birleştirirken) özel bir işlev bekleyen ve özel davranışa sahip yeni bir şablon döndüren bir işlevin içine sararak yapın.

    const createTemplate = fn => function (strings, ...defaults) {
      const [first, ...rest] = strings;
      return (...values) => rest.reduce((acc, curr, i) => {
        return acc + fn(values[i], defaults[i]) + curr;
      }, first);
    };

Daha sonra, örneğin, gömülü html, css, sql, bash yazarken parametrelerden otomatik olarak kaçan veya sterilize eden şablonlar yazabilirsiniz ...

    function sqlSanitize(token, tag) {
      // this is a gross simplification, don't use in production.
      const quoteName = name => (!/^[a-z_][a-z0-9_$]*$/.test(name) ? `"${name.replace(/"/g, '""')}"` : name);
      const quoteValue = value => (typeof value == 'string' ? `'${value.replace(/'/g, "''")}'` : value);
      switch (tag) {
        case 'table':
          return quoteName(token);
        case 'columns':
          return token.map(quoteName);
        case 'row':
          return token.map(quoteValue);
        default:
          return token;
      }
    }

    const sql = createTemplate(sqlSanitize);

Bu saf (tekrar ediyorum, saf! ) Sql şablonuyla aşağıdaki gibi sorgular oluşturabiliriz:

    > q  = sql`INSERT INTO ${'table'} (${'columns'})
    ... VALUES (${'row'});`
    > q('user', ['id', 'user name', 'is"Staff"?'], [1, "O'neil", true])
    // `INSERT INTO user (id,"user name","is""Staff""?")
    // VALUES (1,'O''neil',true);`
  1. Yerine koyma için adlandırılmış parametreleri kabul edin: Önceden verilmiş olana dayalı çok zor olmayan bir egzersiz. Bu diğer cevapta bir uygulama var .

  2. Dönüş nesnesinin a gibi davranmasını sağlayın 'string': Bu tartışmalı, ancak ilginç sonuçlara yol açabilir. Bu diğer cevapta gösterilmiştir .

  3. Çağrı sitesinde genel ad alanı içindeki parametreleri çözün:

Size yeniden kullanılabilir şablon değişmezlerini veriyorum:

Eh, OP'nin gösterdiği şey bu, komutu kullanarak, evilyani, eki eval. Bu eval, sadece genel (veya pencere) nesneye aktarılan değişken adı aranarak yapılabilir . Nasıl yapılacağını göstermeyeceğim çünkü hoşuma gitmiyor. Kapanışlar doğru seçimdir.


2

Bu benim en iyi girişimim:

var s = (item, price) => {return `item: ${item}, price: $${price}`}
s('pants', 10) // 'item: pants, price: $10'
s('shirts', 15) // 'item: shirts, price: $15'

Genelleştirmek için:

var s = (<variable names you want>) => {return `<template with those variables>`}

E6'yı çalıştırmıyorsanız, şunları da yapabilirsiniz:

var s = function(<variable names you want>){return `<template with those variables>`}

Bu, önceki cevaplardan biraz daha özlü görünüyor.

https://repl.it/@abalter/reusable-JS-template-literal


2

Genelde kötülüğü kullanmaya karşıyım eval()ama bu durumda mantıklı:

var template = "`${a}.${b}`";
var a = 1, b = 2;
var populated = eval(template);

console.log(populated);         // shows 1.2

Daha sonra değerleri değiştirir ve eval () öğesini tekrar çağırırsanız, yeni sonucu alırsınız:

a = 3; b = 4;
populated = eval(template);

console.log(populated);         // shows 3.4

Bir fonksiyonda istiyorsanız, o zaman şöyle yazılabilir:

function populate(a, b){
  return `${a}.${b}`;
}

Şablonu içeren bir fonksiyon yazıyorsanız kesinlikle kullanmamalısınız eval.
Bergi

@Bergi Neden? Uygulamanızdan ne kadar farklı?
isapir

2
"Bilmemin" nedenleri, dinamik olarak oluşturulmuş herhangi bir kod için geçerlidir. Fonksiyonu, sonucu eval()açıkça çağırmadan oluşturacak şekilde yazmak, tamamen aynıdır eval(), bu nedenle, yalnızca kodu okumayı zorlaştırdığı için hiçbir faydası yoktur.
isapir

1
Kesinlikle. Ve populateişleviniz kodu dinamik olarak oluşturmadığından, evaltüm dezavantajlarıyla birlikte kullanmamalıdır .
Bergi

6
işleviniz sadece function populate(a,b) { return `${a}.${b}`; }eval hiçbir şey
eklemeyebilir

1

GÜNCELLENDİ: Aşağıdaki cevap tek değişken isimleriyle sınırlıdır, bu nedenle: gibi şablonlar 'Result ${a+b}'bu durum için geçerli değildir. Ancak her zaman şablon değerleriyle oynayabilirsiniz:

format("This is a test: ${a_b}", {a_b: a+b});

ORİJİNAL CEVAP:

Önceki cevaplara dayanarak, ancak daha "kolay" bir yardımcı program işlevi oluşturuyor:

var format = (template, params) => {
    let tpl = template.replace(/\${(?!this\.)/g, "${this.");
    let tpl_func = new Function(`return \`${tpl}\``);

    return tpl_func.call(params);
}

Faturayı aynen şu şekilde yapabilirsiniz:

format("This is a test: ${hola}, second param: ${hello}", {hola: 'Hola', hello: 'Hi'});

Ve ortaya çıkan dize şöyle olmalıdır:

'This is a test: Hola, second param: Hi'

Bunun gibi bir şablona ne dersiniz? `Result: ${a+b}`
Atiris

1
Merhaba @Atiris, haklısın, bu bir sınırlama, cevabımı güncelledim.
Roberto

1

Oldukça basit bir şey arıyorsanız (sadece sabit değişken alanlar, hesaplama yok, koşullu…) ancak bu, IE 8,9,10,11 gibi şablon dizesi desteği olmayan tarayıcılarda istemci tarafında da işe yarıyorsa

İşte başlıyoruz:

fillTemplate = function (templateString, templateVars) {
    var parsed = templateString;
    Object.keys(templateVars).forEach(
        (key) => {
            const value = templateVars[key]
            parsed = parsed.replace('${'+key+'}',value)
        }
    )
    return parsed
}

Bu, her değişken için bir arama yapacak. Bu modülde uyguladığım tüm olayları aynı anda değiştirmenin başka bir yolu daha var: safe-es6-şablonu
Aalex Gabi

1

Ben yazmaktan gerekli ekstra fazlalık de rahatsız oldu this.ben de böyle değişkenleri genişletmek için regex'i eklendi, böylece her seferinde .aiçin this.a.

Çözüm:

const interp = template => _thisObj =>
function() {
    return template.replace(/\${([^}]*)}/g, (_, k) =>
        eval(
            k.replace(/([.a-zA-Z0-9$_]*)([a-zA-Z0-9$_]+)/, (r, ...args) =>
                args[0].charAt(0) == '.' ? 'this' + args[0] + args[1] : r
            )
        )
    );
}.call(_thisObj);

Şöyle kullanın:

console.log(interp('Hello ${.a}${.b}')({ a: 'World', b: '!' }));
// outputs: Hello World!

1

Bu işi kolayca yapabilen bir npm paketi yayınlıyorum. Bu cevaptan derinden ilham aldım .

const Template = require('dynamic-template-string');

var tpl = new Template('hello ${name}');

tpl.fill({name: 'world'}); // ==> 'hello world';
tpl.fill({name: 'china'}); // ==> 'hello china';

Uygulaması son derece basittir. Beğenmeni dilerim.


module.exports = class Template {
  constructor(str) {
    this._func = new Function(`with(this) { return \`${str}\`; }`);
  }

  fill(data) {
    return this._func.call(data);
  }
}

1

satır içi ok işlevini şu şekilde kullanabilirsiniz, tanım:

const template = (substitute: string) => `[^.?!]*(?<=[.?\s!])${substitute}(?=[\s.?!])[^.?!]*[.?!]`;

kullanımı:

console.log(template('my replaced string'));

1

Çalışma zamanı şablon dizesi

var templateString = (template, values) => {
    let output = template;
    Object.keys(values)
        .forEach(key => {
        output = output.replace(new RegExp('\\$' + `{${key}}`, 'g'), values[key]);
    });
    return output;
};

Ölçek

console.debug(templateString('hello ${word} world', {word: 'wonderful'}));

0

const fillTemplate = (template, values) => {
  template = template.replace(/(?<=\${)\w+(?=})/g, v=>"this."+v);
  return Function.apply(this, ["", "return `"+template+"`;"]).call(values);
};

console.log(fillTemplate("The man ${man} is brother of ${brother}", {man: "John", brother:"Peter"}));
//The man John is brother of Peter

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.