1. A Normal Template String vs. a Tagged Template
Code:
const author = 'zhangxinxu';
function tag(arr, exp) {
return `${arr[0]}${exp}`;
}
const normal = `write by ${author}`;
const tagged = tag`write by ${author}`;
console.log(normal);
console.log(tagged);
Result:
2. What the Tag Function Receives
Code:
const author = 'zhangxinxu';
function inspectTag(arr, exp1, exp2) {
return {
arr0: arr[0],
arr1: arr[1],
exp1,
exp2
};
}
const parts = inspectTag`write by ${author}, welcome to share!`;
console.log(parts);
Result:
3. A replace() Function Can Imitate the Idea
Code:
const author = 'zhangxinxu';
function replaceTemplate(str) {
return str.replace(/([\w\W]+)\$\{(\w+)\}([\w\W]+)/, function (matches, $1, $2, $3) {
const scope = { author };
return $1 + scope[$2] + $3;
});
}
const result = replaceTemplate('write by ${author}, welcome to share!');
console.log(result);
Result:
4. Known Structure, Dynamic Processing: Invitation Text
Code:
const data = {
name: 'Deng Tie',
sex: 0,
role: 1,
time: 1640678098887
};
const invite = function (arrs, nameExp, sexExp, roleExp, timeExp) {
let strName = nameExp;
let strSex = ['Mr.', 'Ms.'][sexExp];
const role = {
'1': 'contestant',
'2': 'judge',
'3': 'scorekeeper',
'4': 'photographer'
};
let strRole = role[roleExp];
let strTime = new Date(timeExp).toLocaleDateString(undefined, {
year: 'numeric',
month: 'long',
day: 'numeric'
});
let output = [arrs[0]];
[strName, strSex, strRole, strTime].forEach((str, index) => {
output.push(str, arrs[index + 1] || '');
});
return output.join('');
};
let content = invite`Sincerely invite ${data.name} ${data.sex} to participate as a ${data.role} on ${data.time} in the Shanghai Zhangjiang Cup Fishing Competition.
Organizer: Shanghai Pudong Fishing Association`;
console.log(content);
Result:
5. HTML Tagged Template with Event Binding
Code:
const render = function (data, container) {
container.innerHTML = '';
container.append(element(data));
};
const html = function (arr, ...keys) {
let result = [arr[0]];
keys.forEach(function (key, i) {
if (typeof key == 'function') {
result.push(i, arr[i + 1]);
} else {
result.push(key, arr[i + 1]);
}
});
let template = document.createElement('template');
template.innerHTML = result.join('');
template.content.querySelectorAll('*').forEach(node => {
let attrs = node.attributes;
for (let i = attrs.length - 1; i >= 0; i--) {
let attr = attrs[i].name;
let value = attrs[i].value;
if (/^on[a-z]+$/i.test(attr) && !isNaN(parseFloat(value))) {
node.removeAttribute(attr);
node.addEventListener(attr.replace(/^on/, ''), keys[Number(value)]);
}
}
});
return template.content;
};
let todos = ['Eat', 'Sleep', 'Beat Doudou'];
function addTodo() {
todos.push(document.querySelector('#task').value);
render(todos, document.querySelector('#app'));
}
let element = function (todos) {
return html`Task list (${todos.length})
${todos.map(todo => `- ${todo}
`).join('')}
`;
};
render(todos, document.querySelector('#app'));
Result:
6. A Small DSL: URL Escaping
Code:
function url(arr, ...values) {
let result = [arr[0]];
values.forEach((value, index) => {
result.push(encodeURIComponent(value), arr[index + 1]);
});
return result.join('');
}
const keyword = 'tagged templates & DSL';
const page = 2;
const api = url`/search?q=${keyword}&page=${page}`;
console.log(api);
Result:
Escaped URL