css-vars-ponyfill
通过css变量来实现网页换肤的过程中,会呈现兼容性问题。
为了解决ie,qq,百度浏览器等兼容性问题,引入css-vars-ponyfill,然而在ie浏览器下,css-vars-ponyfill 的在nextjs下体现不佳,次要缺点是因为页面是服务端渲染,因而用户在看到界面后,动静主题色等款式不能很快渲染好,而是有一个过渡的工夫(css-vars-ponyfill 仅反对client-side),色彩会存在显著替换的过程用户体验差。通过浏览源码能够看到,cssVars须要等到浏览器contentLoaded之后,才会触发,否则始终监听dom的data content事件,这就导致了体验上的问题。
解决方案
1.解析速度
通过把间接去除document.readyState !== 'loading'
这样的限度条件使得浏览器在解析到,而后更改css-vars-ponyfill 的引入形式(旧的引入形式是在nextjs中的mainjs中引入module,而后间接调用cssVars(),这样在调用到ponyfill的脚本前还会解析其余不相干的chunk,为了更快的解析css变量,须要手动抉择插入地位),更改之后的css-vars-ponyfill 通过找到css变量的地位(nextjs 通过将不同组件下的style,对立打包在header外面),而后将更改后的ponyfill 插入到style 之后进行调用,这一步抉择在服务端渲染的 _document.tsx 文件中更改。
2.解析稳定性
通过手动更改文件解析地位,以及对源码的条件触发机制进行相干更改,首页色彩渲染速度有了肯定晋升。然而仍存在一个问题,即通过路由跳转的界面,如果有新的style chunk,插入时不能进行无效的css变量解析(已尝试配置cssVars的option 关上MutationObserver)。
因而,解决方案是通过判断UA,来让ie等浏览器下所有的路由通过a标签跳转,触发css-ponyfill的从新解析执行。
export function browser() {
const UA = window.navigator.userAgent
if (UA.includes("qqbrowser")) return "qqbrowser"
if (UA.includes("baidu")) return "baidu"
if (UA.includes("Opera")) return "Opera"
if (UA.includes("Edge")) return "Edge"
if (UA.includes("MSIE") || (UA.includes("Trident") && UA.includes("rv:11.0")))
return "IE"
if (UA.includes("Firefox")) return "Firefox"
if (UA.includes("Chrome")) return "Chrome"
if (UA.includes("Safari")) return "Safari"
}
type CommonLinkProps = {
children: ReactElement
href?: string
target?: string
outerLink?: boolean
styles?: unknown
}
export default function CustomLink(props: CommonLinkProps) {
const { children, href, target, as, outerLink, styles = emptyStyles } = props
const [isIE, setIE] = useState<boolean>(false)
const cloneEl = (c: ReactElement, props?: any) =>
React.cloneElement(c, { href: as ?? href, target, ...props })
useEffect(() => {
if (["IE", "qqbrowser", "baidu"].includes(browser())) {
setIE(true)
}
}, [])
function renderLink() {
if (Children.only(children).type === "a") {
const node = cloneEl(children as ReactElement)
return node
} else {
let fn: () => void | null = null
if (outerLink) {
fn = () => {
window.open(as ?? href)
}
} else {
fn = () => {
window.location.href = as ?? href
}
}
const node = cloneEl(children as ReactElement, {
onClick: () => {
fn()
},
})
return node
}
}
return (
<>
{!href ? (
children
) : isIE ? (
renderLink()
) : (
<Link {...props}>{children}</Link>
)}
<style jsx>{styles}</style>
</>
)
}
这里children的type 抉择了ReactElement
,而不是插槽中通常反对的ReactNode
次要是不想思考直接插入字符串这种状况,会减少问题的复杂度,因而间接在type这层做限度。还有Fragments 也没有思考,且没有找到无效的Fragments 类型,没法在ReactNode 中把它Omit掉,nextjs 外面的Link 如果首层插入了Fragments 后,也无奈失常跳转,可能起因也是无奈再Fragments 下面绑定无效的事件吧,目前Fragments(16.13.1) 只反对key属性,心愿后续能够优化。
发表回复