我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!
技术点概览
一句话概括,文章包含编辑器、渲染器两个码上掘金代码块,采用 BroadcastChannel 实现代码块通信,将编辑器中内容传递到渲染器中,解析代码,注册为组件使用。
前言
相信在座各位都体验过码上掘金了,什么?没玩过,那快点这里 ➡️ 码上掘金开始表演你的 hello world吧。
最近看(白嫖)站内大佬们文章时,看到码上掘金的时候,墙上的📅日历就像是哗哗作响,脑子里闪过在CodePen、JSFiddle、RunJS这些名字,多年前的今天,在整理前端的入门文章时,想嵌入可预览的代码块,可选择的线上代码分享平台还是 CodePen,但是因为这服务吧,远在他国,网络来去不自如。
😮💨当时也是无奈,只能试着自己搞一搞。
现在嘛,技能熟练度涨进了那么一丢丢,可以试着带大家伙一起搞一搞😘。
3,2,1 上链接
前往文章下方体验效果 去体验
言归正传
要做什么?
这是个好问题,我们需要一个编辑区域和一个预览区域。
编辑器(编辑区域)
- 文章中可以展示编写的
Hello World组件效果 - 文章浏览者可以自由的把
Hello World改成已点赞👍
渲染器(预览区域)
- 代码块
Hello World组件,可以在Import Hello World代码块中使用 - 代码块
Hello World组件的改动,同步在Import Hello World代码块中
在其他场景下,这些一般在一个项目中,通信的方式有很多,但是在文章中的码上掘金代码块场景下,两个代码块要如何通信呢?
怎么做?
这不是问题
如何通信
还记得上面说的BroadcastChannel么,不熟悉的同学请在公屏上扣1,呸呸呸,请自行复制,右上方点击搜索🔍。
/**
* 初始化跨页面通信
* @return {BroadcastChannel}
*/
function initMessage () {
const broadcastChannel = new BroadcastChannel('shareComponent')
return broadcastChannel
}
也许,有些事情,就像爱情一样,只需要简简单单就可以了。
通信
那么同学们,通信的问题就解答完了,接下来让我们来 new 一个 编辑器 组件,再 new 一个 渲染器组件。
在 编辑器里,我们初始化编辑器,和通信钩子,对外提供切换主题、重置代码的事件,当然还有很重要的代码更新通知。
# 编辑器
const editor = initEditor()
const message = initMessage()
message.onmessage = (e) => {
const { type } = e.data
switch (type) {
case 'toggle-theme': {
randomTheme()
break
}
case 'reset': {
Object.assign(data, initData())
editor.updateCode(data.content)
break
}
}
}
editor.onUpdate(() => {
message.postMessage({
type: 'update-code',
data: data.content
})
})
在 渲染器里,我们同样初始化通信钩子,监听代码更新的通知,用来接收编辑器的代码。
# 渲染器
const message = initMessage()
message.onmessage = (e) => {
const { type, data } = e.data
switch (type) {
case 'update-code': {
renderComponent('myButton', data)
break
}
}
}
到这里,两个代码块已经可以愉快的交流了,代码块联动后的码上掘金会有怎样的魔力呢,请尽情释放你的光吧~
附带赠送的组件渲染
同学们,到这里我们已经实现了,在编辑器中编辑代码,渲染器中同步获取代码,那么接下来,我们把获取的组件代码,更新到对应的组件。
// 注册组件
app.component(name, formatComponent(content))
我们拿到的是SFC格式的Vue组件,还需要一丢丢的转换工作。
const ComponentRegexs = {
template: {
match: /<template.*?>([\s\S]+?)</template>/gi,
replace: /<template>|</template>/g
},
script: {
match: /<script.*?>([\s\S]+?)</script>/gi,
replace: /<script>|</script>|export default/g
},
style: {
match: /<style.*?>([\s\S]+?)</style>/gi,
replace: /<style>|</style>/g
}
}
/**
* 格式化组件内容
* @param content
*/
function formatComponent (content) {
const formatRegexs = Object.keys(ComponentRegexs)
const result = {}
formatRegexs.forEach(k => {
const waitRegex = ComponentRegexs[k]
const canMatch = content.match(waitRegex.match)
if (canMatch) {
result[k] = canMatch.at(0).replace(waitRegex.replace, '')
}
})
let script
script = eval(`script = ${result.script}`)
return Object.assign({
template: result.template
}, typeof script === 'object' ? script : {})
}
在这里,大家如果体验过示例,就会发现样式并没有生效,因为就没有进行处理呀😄。
简单说下,之前实践的思路是,动态将style插入DOM,配合组件名称锁定CSS作用域,但是考虑到时过境迁,也许有其他更好的方案,就暂时搁置。
好了,今天的小葵花课堂就到这里结束了,有什么想法,我们在评论区进行讨论,感谢🎉。
效果体验
编辑器
渲染器
幕后花絮
本节目由码上掘金行业独家赞助(蹭蹭),欲知更多代码详情,请点击文章中码上掘金代码块了解更多。
由CodeFlask、传统色彩、Vue及我本人提供技术支持。
🎉另外感谢大家伙收看本节目,祝各位中秋快乐,万事顺心。
对了,班里最后走的同学记得把灯关了,围观的大家伙也要记得点个赞哦。
彩蛋
最后,找一找,如何切换编辑器主题颜色呢?