你不知道的模板字符串
在模板字符串之前,对于字符串的处理往往会碰到以下问题:
-
拼接代码不优雅
// ES5 方式 var name = "ErMao"; var age = 28; var message = "Hello, my name is " + name + " and I am " + age + " years old."; console.log(message); // "Hello, my name is ErMao and I am 28 years old." -
多行文本处理复杂
// ES5 方式 - 不直观的多行字符串 var multiLine1 = "This is line one.\nThis is line two."; var multiLine2 = "This is line one.\ This is line two."; // 注意:这种方式第二行前的缩进也会被算作字符串内容 -
动态HTML生成不优雅
// ES5 方式 - 构建 HTML var item = { name: "Coffee", price: 2.5 }; var htmlSnippet = '<div class="item">\n <h3>' + item.name + '</h3>\n <p>Price: $' + item.price + '</p>\n</div>';
以上问题都基于对字符串拼接没有一个好的处理方式。
在ES6之后就出现了模板字符串,对于以上的代码有了更加优雅的写法。
字符串插值
在模板字符串中,最重要的特性就是字符串插值。通过使用${},可以任何有效的JS表达式嵌入到字符串中。
const name = "ErMao";
const age =28;
// 使用模板字符串
const message = `Hello, my name is ${name} and I am ${age} years old.`;
console.log(message); // "Hello, my name is ErMao and I am 28 years old."
// ${} 内可以是任意表达式
const calculation = `Five plus ten is ${5 + 10}.`;
console.log(calculation); // "Five plus ten is 15."
function double(x) {
return x * 2;
}
const functionCall = `The double of 8 is ${double(8)}.`;
console.log(functionCall); // "The double of 8 is 16."
标签模板(Tag Function)
这个方式一般很少使用到,但是思路是非常的巧妙的。在 CSS IN JS 、 hyperHTML中,都能发现其作用。
css in js 的核心是需要将css 模块化,而通过js的方式能够将css有效进行模块化操作。有了 Tag Function 就更好的对css的字符串进行操作处理。
// 以下是主题切换的例子
// 主题上下文
const ThemeContext = {
currentTheme: 'light',
themes: {
light: {
primary: '#007bff',
background: '#ffffff',
text: '#333333',
border: '#dee2e6'
},
dark: {
primary: '#4dabf7',
background: '#1a1a1a',
text: '#ffffff',
border: '#495057'
}
}
};
// 主题标签函数
function themed(strings, ...values) {
return function(elementProps = {}) {
const className = `themed-${Math.random().toString(36).substr(2, 9)}`;
const theme = ThemeContext.themes[ThemeContext.currentTheme];
let styles = '';
strings.forEach((string, i) => {
styles += string;
if (i < values.length) {
const value = values[i];
// 处理主题值
if (typeof value === 'function') {
styles += value(theme, elementProps);
} else if (value && value.theme) {
styles += theme[value.theme] || value.fallback || '';
} else {
styles += value;
}
}
});
const styleElement = document.createElement('style');
styleElement.textContent = `.${className} { ${styles} }`;
document.head.appendChild(styleElement);
return className;
};
}
// 使用主题
const themedButton = themed`
background: ${theme => theme.primary};
color: white;
border: 1px solid ${theme => theme.border};
padding: 12px 24px;
border-radius: 6px;
cursor: pointer;
margin: 8px;
transition: all 0.3s ease;
&:hover {
background: ${theme => theme.primary}dd;
transform: translateY(-1px);
}
`;
// 主题切换函数
function switchTheme(themeName) {
ThemeContext.currentTheme = themeName;
// 重新应用样式
document.querySelectorAll('[data-themed]').forEach(element => {
const originalClass = element.className.split(' ')[0];
const newClass = themedButton();
element.className = element.className.replace(originalClass, newClass);
});
}
// 创建主题按钮
const btn1 = document.createElement('button');
btn1.className = themedButton();
btn1.textContent = '主题按钮';
btn1.setAttribute('data-themed', 'true');
const btn2 = document.createElement('button');
btn2.className = themedButton();
btn2.textContent = '另一个主题按钮';
btn2.setAttribute('data-themed', 'true');
// 主题切换按钮
const switchBtn = document.createElement('button');
switchBtn.textContent = '切换主题';
switchBtn.onclick = () => {
const newTheme = ThemeContext.currentTheme === 'light' ? 'dark' : 'light';
switchTheme(newTheme);
};
document.body.appendChild(btn1);
document.body.appendChild(btn2);
document.body.appendChild(switchBtn);