模板字符串的应用,仿styled-compents
模板字符串,也叫模板字面量.模板字符串是用反引号(`)包起来的语法结构.通常用于大量复杂的文字插入变量,替换点位符用.
[参考]
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Template_literals
语法
// 单行
`hello world!`
// 多行
`
白日依山尽,
黄河入海流.
`
// 模板替换
`姓名:${name},性别:${gender}`
// 带标签模板
tagTrim`我的名字叫${name}.`
使用变量和表达式
在模板字符串中,可以用${表达式}
,{}
可以是任何变量,可以是表达式,甚至函数.
最终结果相当于表达式的最终值,转成string的效果.
举例:
let str="javascript"
// out: hello javascript
console.log(`hello ${str}`)
// out: 1+1=2
console.log(`1+1=${1+1}`)
// out: obj:[object Object]
console.log(`obj:${{a:1,"b":2}}`)
let func=(a,b)=>{return a+b}
// func:3
console.log(`func:${func(1,2)}`)
嵌套:
// hello javascript 3
console.log(`
hello ${`javascript ${1+2}`}
`)
标签模板
以上这种都很常见,在php中也是差不多的语法.
JS的模板字符串还有一种用法,就是标签语法.
语法:
func `模板字符串内容`
func (str[],...args){
// str[],所有字符串的数组,使用${}分开,数组数量,大于${}的数量
// ...args,其他${变量}结果
}
如下实现 一个"echo"标签,第1个参数为数组['姓名: ',',年龄:','']
,第2参数:${name}的值
,第3个参数:${18+10}=28
echo `姓名: ${name},年龄:${18+10}`
实际上是一个函数.相当于 echo(xxx)
例子,echo
const echo=(strs,...args)=>{
let message='';
strs.forEach((str,index)=>{
message+=`${str}${args[index]??''}`
})
console.log(message)
}
let name="张三";
echo `姓名: ${name},年龄:${18+10}`
如上代码输出: 姓名: 张三,年龄:28
String.raw
第1个参数,中多出了一个raw属性,raw是不可修改的特殊属性.
参考: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/raw
raw属性干什么用的呢?
原样字符串,不经过转义后字符串. "\n"在字符串中表示换行. 在raw表示两个字符\
和n
,不被转义.
举例:
console.log("hello\nworld");//输出: hello 换行 world
如果要原样输出,改一下.
const echo=(strs,...args)=>{
let message='';
strs.raw.forEach((str,index)=>{
message+=`${str}${args[index]??''}`
})
console.log(message);
}
let name="张三";
echo `姓名: ${name},\n年龄:${18+10}`
输出: 姓名: 张三,\n年龄:28
使用 strs.raw
代替strs.
es6 系统提供了一个自带的标签函数. String.raw
上面可以写成
String.raw `姓名: ${name},\n年龄:${18+10}`
也可以直接调用String.raw,但不建议直接使用.
String.raw({raw:['姓名: ',',\n年龄:','']},name,18+10)
上面echo 函数也可以改成.
// const echo=(strs,...args)=>{
// let message='';
// strs.raw.forEach((str,index)=>{
// message+=`${str}${args[index]??''}`
// })
// console.log(message);
// }
const echo=(strs,...args)=>console.log(String.raw(strs,...args))
let name="张三";
echo `姓名: ${name},\n年龄:${18+10}`
应用例子
styled-compents
styled-compents 是css-in-js 的react 插件. 可以像写JS一样写css. 不像sass,less一样需要编译.
https://styled-components.com/
styled-compents 就是典型的tagFun 应用. 我们看一下styled的语法:
创建一个带样式的button.
const Button = styled.button`
background: transparent;
border-radius: 3px;
border: 2px solid #BF4F74;
color: #BF4F74;
margin: 0 1em;
padding: 0.25em 1em;
`
<Button>Normal Button</Button>
styled.button
就是一个标签函数. 原理就是利用标签模板函数,解析样式.
原生JS如何实现?
const Button=document.createElement("button");
Button.style=`background: transparent;
border-radius: 3px;
border: 2px solid #BF4F74;
color: #BF4F74;
margin: 0 1em;
padding: 0.25em 1em;`
Button.innerHTML="提交"
document.body.appendChild(Button)
省略了创建button的过程.
const styled=function(){};
styled.button=function(css,...vals){
const button= document.createElement('button');
button.style=String.raw(css,...vals);
return button;
}
styled.props=function(){}
const Button = styled.button`
background: transparent;
border-radius: 3px;
border: 2px solid #BF4F74;
color: #BF4F74;
margin: 0 1em;
padding: 0.25em 1em;
`
Button.innerHTML="提交"
document.body.appendChild(Button)
改进一下成通用组件.
const styled= new function() {
this.version="1.0"
function createElement(name,css={},vals=[]){
const dom= document.createElement(name);
if(!css.raw){
return dom;
}
dom.style=String.raw(css,...vals);
return dom;
}
return new Proxy(this,{
get:function(target,prop){
if (prop in target){
return target[prop]
}
return function(css,...vals){
return createElement(prop,css,vals)
}
}
});
}
const Button=styled.button`background: transparent;
border-radius: 3px;
border: 2px solid #BF4F74;
color: #BF4F74;
margin: 0 1em;
padding: 0.25em 1em;
`
Button.innerHTML="提交"
const Div=styled.div`background:#ccc;height:100px;`
Div.innerHTML="hello world";
Div.appendChild(Button);
document.body.appendChild(Div)
原作者:阿金
本文地址:https://hi-arkin.com/archives/Template_literals.html