四、样式隔离
上节,说到样式问题,我们先定义一个组件 Text。
// Text.js 新增
const { html, css, define } = require("hcdr")
const template = ({ title }) => {
return html`<span class="text">${title}</span>`
}
const style = params => {
let { type } = params || {}
let colors = {
default: "#606266",
primary: "#409EFF",
success: "67C23A",
info: "909399",
warning: "E6A23C",
danger: "F56C6C"
}
let color = type && colors[type] ? colors[type] : colors["default"]
return css`
.text {
margin: 0 4px;
color: ${color};
}
`
}
module.exports = define("Text", { template, style })
进行组件 Text 复用
// test3.js 新增
const { html, render, define } = require("hcdr")
const Text = require("./Text")
const App = define("App", {
template: () => {
return html`<div id="app">
${Text({ title: "Default" })} ${Text(
{ title: "Primary" },
{ type: "primary" }
)} ${Text({ title: "success" }, { type: "success" })} ${Text(
{ title: "info" },
{ type: "info" }
)} ${Text({ title: "warning" }, { type: "warning" })} ${Text(
{ title: "danger" },
{ type: "danger" }
)}
</div> `
}
})
const code = render(App)
console.log(code)
测试发现样式正常生成,下列样式
.text {
margin: 0 4px;
color: #606266;
}
.text {
margin: 0 4px;
color: #409EFF;
}
.text {
margin: 0 4px;
color: 67C23A;
}
.text {
margin: 0 4px;
color: 909399;
}
.text {
margin: 0 4px;
color: E6A23C;
}
.text {
margin: 0 4px;
color: F56C6C;
}
这样最终的效果只会显示最后一种样式,这不是我们想要的结果,因此需要对样式进行隔离。
这里考虑用vue的scope样式隔离方法:在标签和样式上同时添加标识属性。
这里想当然对 define 方法动手了
// hcdr/index.js 修改
function define(name, { template, style, script }) {
return function component(data, css) {
// 本来想用时间戳居然会重复...
// 直接采用 nanoid 生成8位数字和小写字母的字符串
// npm i nanoid@3 ,该版本有问题
const id = `data-${uuid()}`
// 样式添加属性
let strCss = typeof style == "function" ? style(css || {}) : ""
// 把样式中含有","或".xxx {" 替换加上id
strCss = strCss
.replace(/\s+,/g, `[${id}], `)
.replace(/\.[\w-]+\s+\{/g, rule => {
return `${rule.replace("{", "").trim()}[${id}] {`
})
container.style.push(strCss)
// 收集起脚本
container.script.push(script || "")
// 标签添加上id
let code = template(data || {})
// 取出字符串中标签名,遍历替换所有标签
code = compileTemplate(code, id)
return code
}
}
// 编译模板
function compileTemplate(str, id) {
let tags = []
const regex = /<([a-z][a-z0-9]*)\b[^>]*>/gim
let match
while ((match = regex.exec(str))) {
tags.push(match[1])
}
tags = [...new Set(tags)]
tags.forEach(tag => {
str = str.replace(new RegExp(`\\<${tag}`, "g"), `<${tag} ${id}`)
})
return str
}
上面,就是把样式和模板字符串进行替换添加标识
运行一把试试, 结构
<!-- 结构内容 -->
<div data-xhay58qv class="app">
<span data-5qjwn21h data-xhay58qv class="text">Default</span>
<span data-yq5n3r12 data-xhay58qv class="text">Primary</span>
<span data-1yl4w6tt data-xhay58qv class="text">success</span>
<span data-jmsi06lf data-xhay58qv class="text">info</span>
<span data-3wo42ee0 data-xhay58qv class="text">warning</span>
<span data-3q52u3fc data-xhay58qv class="text">danger</span>
</div>
样式
.text[data-5qjwn21h] {
margin: 0 4px;
color: #606266;
}
.text[data-yq5n3r12] {
margin: 0 4px;
color: #409EFF;
}
.text[data-1yl4w6tt] {
margin: 0 4px;
color: #67C23A;
}
.text[data-jmsi06lf] {
margin: 0 4px;
color: #909399;
}
.text[data-3wo42ee0] {
margin: 0 4px;
color: #E6A23C;
}
.text[data-3q52u3fc] {
margin: 0 4px;
color: #F56C6C;
}
可以看出父组件生成的标识会添加到子组件上,样式可以达到了效果。 下节,我们看看异步数据请求存在的问题