tl;dr:有可能使一个可重用的模板文字吗?

我一直试图使用模板文字,但我想我只是不明白,现在我感到沮丧。我是说,我觉得我懂了,但"它"不应该是这样的,也不应该是这样的。情况应该有所不同。

我看到的所有示例(甚至是带标签的模板)都要求“替换”在声明时完成,而不是在运行时完成,这对模板来说似乎完全没有用。也许我疯了,但“模板”对我来说是一个包含标记的文档,这些标记在你使用它时被替换,而不是在你创建它时,否则它只是一个文档(即字符串)。模板存储与令牌作为令牌&这些令牌评估时,你…评估它。

每个人都举了一个可怕的例子:

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

这很好,但如果我已经知道a,我只会返回'一文不值asd'或返回'一文不值'+a。有什么意义?认真对待。好吧,重点是懒惰;加号少,可读性强。太好了。但这不是模板!恕我直言。MHO才是最重要的!问题,恕我直言,是模板在声明时被求值,所以,如果你这样做,恕我直言:

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

由于没有声明expletive,它输出类似于My undefined template的内容。超级。实际上,至少在Chrome中,我甚至不能声明模板;它抛出一个错误,因为没有定义咒骂。我需要的是能够在声明模板后进行替换:

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

然而,我不明白这是怎么可能的,因为这些都不是真正的模板。即使你说我应该使用标签,不,它们不起作用:

> 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...

这一切都让我相信模板文字的名字是可怕的错误,应该被称为他们真正的名字:heredocs。我猜“字面”部分应该提示我(在,不可变)?

我遗漏了什么吗?是否有一种(好的)方法来创建一个可重用的模板文字?


我给你,可重用的模板文字

> 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!

这里是一个简单的“helper”函数…

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

...让它“更好”。

我倾向于称它们为模板肠,因为它们产生扭曲感觉的区域。


当前回答

如果你不想使用有序参数或上下文/命名空间来引用模板中的变量,例如${0},${this. xml。Something},或者${data。Something},你可以有一个模板函数来为你处理范围。

如何调用这样一个模板的例子:

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

模板函数:

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);
  }
}

在这种情况下,你只需要传递一个返回ES6模板文字的函数(在这个例子中,我使用了一个箭头函数)。我认为要得到我们所追求的那种可重用的插值,这是一个小小的权衡。

这里是GitHub: https://github.com/Adelphos/ES6-Reuseable-Template

其他回答

简单的答案是使用_。lodash中的模板

// 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!'

当我看到它的时候,我非常头疼。javascript中的文字模板非常酷,但它们****可重用或带有动态值。但解决方法非常简单。事实上,在花了几天时间编写解析器、格式化器和其他解决方案后,我不得不踢自己几次。最后在我放弃了这个想法,打算使用胡子或其他模板模块后,它击中了我.....

const DT = function dynamicTemplate(source) { return (new Function(`return \`${source}\``))() }

//let a = 1, b = 2;
//DT("${a} + ${b} equals ${a + b}")
// prints '1 + 2 equals 3'

这就是她写的全部内容。

你可以只使用一行标签模板,比如:

const SERVICE_ADDRESS = (s,tenant) => `http://localhost/${tenant}/api/v0.1/service`;

在客户端代码中,你可以这样使用它:

const myTenant = 'me';
fetch(SERVICE_ADDRESS`${myTenant}`);

如果你使用的是Angular,你可以像下面这样使用@ngx-translate/core包:

import { TranslateDefaultParser } from '@ngx-translate/core';

export class SomeClass {
    public parser = new TranslateDefaultParser();
    test() {
        // outputs "This is my great reusable template!"
        this.parser.interpolate('This is my {{expletive}} reusable template!', { expletive: 'great' });
    }
    ...
}

感谢@Quentin-Engles的出色想法和最佳答案,让我开始了!

但是我将新函数直接存储在一个变量中,而不是每次都返回函数,这样函数和模板文字都只构建一次,而不是每次调用它,就像在Quentin的回答中那样。

const templateString = "Hello ${this.name}.";
var myData = {
    name: "world"    
};

const buildItem = new Function("return `" + templateString + "`;");

console.log(buildItem.call(myData));  // Hello world.

myData.name = "Joe";
console.log(buildItem.call(myData));  // Hello Joe.