UNPKG

2.98 kBJavaScriptView Raw
1import React from 'react'
2
3export const StyleMapContext = React.createContext({})
4
5/**
6 * 将样式表写入到 head 标签内
7 * @param {Object} styleMap
8 */
9export const checkAndWriteIntoHead = (styleMap = {}) => {
10 if (typeof styleMap !== 'object') return
11 Object.keys(styleMap).forEach(wrapper => {
12 const style = styleMap[wrapper]
13 if (style.count > 0) {
14 // 配置样式
15 if (!document.getElementById(wrapper)) {
16 const styleTag = document.createElement('style')
17 styleTag.innerHTML = style.css
18 styleTag.setAttribute('id', wrapper)
19 document.getElementsByTagName('head')[0].appendChild(styleTag)
20 }
21 } else {
22 // 移除样式
23 if (document.getElementById(wrapper)) {
24 document.getElementById(wrapper).remove()
25 }
26 }
27 })
28}
29
30/**
31 * 追加样式
32 * @param {Object} styleMap
33 * @param {Object|Array} style
34 */
35export const append = (styleMap = {}, style) => {
36 if (Array.isArray(style))
37 return style.forEach(theStyle => append(styleMap, theStyle))
38
39 if (typeof style !== 'object') return
40
41 if (!styleMap[style.wrapper]) {
42 styleMap[style.wrapper] = {
43 css: style.css,
44 count: 1
45 }
46 } else {
47 styleMap[style.wrapper].count++
48 }
49
50 if (__CLIENT__) {
51 checkAndWriteIntoHead(styleMap)
52 }
53}
54
55/**
56 * 移除样式
57 * @param {Object} styleMap
58 * @param {*} style
59 */
60export const remove = (styleMap = {}, style) => {
61 if (Array.isArray(style))
62 return style.forEach(theStyle => remove(theStyle))
63
64 if (typeof style !== 'object') return
65
66 if (styleMap[style.wrapper]) {
67 styleMap[style.wrapper].count--
68 }
69}
70
71const idDivStylesContainer = '__KOOT_ISOMORPHIC_STYLES_CONTAINER__'
72
73/**
74 * 分析 HTML 代码,解析已有样式表,将其从 HTML 代码中移除,并返回可以直接写入到 head 标签内的样式表代码
75 * @param {String} html
76 * @returns {String} htmlStyles
77 */
78export const parseHtmlForStyles = (html) => {
79 const matches = html.match(new RegExp(`<div id="${idDivStylesContainer}">(.+)</div>`, 'm'))
80 return {
81 html: html.substr(0, matches.index),
82 htmlStyles: matches[1]
83 }
84}
85
86/**
87 * React 组件: 样式表内容容器
88 */
89export class StylesContainer extends React.Component {
90 static contextType = StyleMapContext
91 render() {
92 return (
93 <div
94 id={idDivStylesContainer}
95 dangerouslySetInnerHTML={{
96 __html: Object.keys(this.context)
97 .filter(id => !!this.context[id].css)
98 .map(id => `<style id="${id}">${this.context[id].css}</style>`)
99 .join('')
100 }}
101 />
102 )
103 }
104}