-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
140 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`loadCss 加载内容 1`] = ` | ||
<style type="text/css"> | ||
body {font-size: 20px} | ||
</style> | ||
`; | ||
|
||
exports[`loadCss 加载内容 2`] = ` | ||
<html> | ||
<head> | ||
<style type="text/css"> | ||
body {font-size: 20px} | ||
</style> | ||
</head> | ||
<body> | ||
</body> | ||
</html> | ||
`; | ||
|
||
exports[`loadCss 加载链接 1`] = ` | ||
<link rel="stylesheet" | ||
href="http://foo.bar/x.css" | ||
> | ||
`; | ||
exports[`loadCss 加载链接 2`] = ` | ||
<html> | ||
<head> | ||
<link rel="stylesheet" | ||
href="http://foo.bar/x.css" | ||
> | ||
</head> | ||
<body> | ||
</body> | ||
</html> | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { loadCss } from './loadCss' | ||
|
||
describe('loadCss', () => { | ||
const createElement = document.createElement.bind(document) | ||
beforeAll(() => { | ||
jest.spyOn(document, 'createElement').mockImplementation((tag: string) => { | ||
const el = createElement(tag) | ||
setTimeout(() => { | ||
if ( | ||
/returnError/.test( | ||
(el as HTMLScriptElement).src || (el as HTMLLinkElement).href, | ||
) | ||
) { | ||
el.onerror?.(new Event('error')) | ||
} else { | ||
el.onload?.(new Event('load')) | ||
} | ||
}, 0) | ||
return el | ||
}) | ||
}) | ||
afterAll(() => { | ||
jest.clearAllMocks() | ||
}) | ||
|
||
test('加载链接', async () => { | ||
const css = await loadCss(`http://foo.bar/x.css`) | ||
const css2 = await loadCss(`http://foo.bar/x.css`) | ||
expect(css.el).toBe(css2.el) | ||
expect(css.el.outerHTML).toMatchSnapshot() | ||
expect(document.documentElement.outerHTML).toMatchSnapshot() | ||
css.destroy() | ||
}) | ||
|
||
test('加载内容', async () => { | ||
const css = await loadCss(`body {font-size: 20px}`) | ||
const css2 = await loadCss(`body {font-size: 20px}`) | ||
expect(css.el).toBe(css2.el) | ||
expect(css.el.outerHTML).toMatchSnapshot() | ||
expect(document.documentElement.outerHTML).toMatchSnapshot() | ||
css.destroy() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { isDataUrl } from './isDataUrl' | ||
import { isUrl } from './isUrl' | ||
import { loadResource, LoadResourceUrlType } from './loadResource' | ||
|
||
const cache: Record<string, HTMLStyleElement> = Object.create(null) | ||
|
||
export interface LoadCssResult { | ||
/** | ||
* 样式元素。 | ||
*/ | ||
el: HTMLStyleElement | ||
|
||
/** | ||
* 销毁函数。 | ||
*/ | ||
destroy: () => void | ||
} | ||
|
||
/** | ||
* 加载 CSS 样式,支持链接和内容。 | ||
* | ||
* @param urlOrContent 链接或内容 | ||
* @example | ||
* ```typescript | ||
* loadCss('https://foo.bar/global.css') | ||
* loadCss(`body { font-size: 20px; }`) | ||
* ``` | ||
*/ | ||
export function loadCss(urlOrContent: string): Promise<LoadCssResult> { | ||
return (urlOrContent in cache | ||
? Promise.resolve(cache[urlOrContent]) | ||
: isUrl(urlOrContent) || isDataUrl(urlOrContent) | ||
? loadResource({ | ||
type: LoadResourceUrlType.css, | ||
path: urlOrContent, | ||
}).then<HTMLStyleElement>(res => res[0] as any) | ||
: new Promise<HTMLStyleElement>(resolve => { | ||
const el = document.createElement('style') | ||
el.setAttribute('type', 'text/css') | ||
if ('textContent' in el) { | ||
el.textContent = urlOrContent | ||
} else { | ||
// @ts-ignore | ||
el.styleSheet.cssText = urlOrContent | ||
} | ||
document.getElementsByTagName('head')[0].appendChild(el) | ||
resolve(el) | ||
}) | ||
).then<LoadCssResult>(el => { | ||
cache[urlOrContent] = el | ||
return { | ||
el: el, | ||
destroy: () => { | ||
delete cache[urlOrContent] | ||
el.parentNode!.removeChild(el) | ||
}, | ||
} | ||
}) | ||
} |