nf-Press —— 在線文檔也可以加載組件和編寫代碼
如果幫助文檔可以加載組件,那麼在介紹的同時就可以運行演示demo,是不是很酷?
如果可以在線修改運行代碼,那麼是不是更容易理解?
上一篇 //www.cnblogs.com/jyk/p/15994934.html 介紹了一下基本功能,這裡介紹一下關於代碼方面的功能。
源碼和演示
//gitee.com/nfpress/nf-press-edit
//nfpress.gitee.io/nf-press-edit/
加載組件、運行組件
Vue提供了一個可以動態加載組件的組件,component 和 defineAsyncComponent,我們可以用其實現我們想要的效果。
註冊組件
我們可以參考動態路由的設置方式來註冊組件:
import { createRouter } from '/nf-press-edit'
// 設置 axios 的 baseUrl
const baseUrl = (document.location.host.includes('.gitee.io')) ?
'/nf-press-edit/' : '/'
export default createRouter({
baseUrl,
components: {
testComponent: () => import('../components/testCode.vue'),
testComponent2: () => import('../components/testCode2.vue')
}
})
- baseUrl: 基礎路由,比如要發佈到 gitee.com 上,就需要根據情況設計第一級路徑。
- components: 需要加載的組件集合,key-value形式,可以註冊多個組件。
這裡的「路由」,只需要定義需要加載的組件即可,文檔的導航路由不需要設置。
存入全局狀態
nf-press 會把註冊的組件存入state,便於使用:
// 註冊組件
if (info.components) {
if (Object.keys(info.components).length > 0) {
const { comp } = state
for(let key in components) {
comp[key] = defineAsyncComponent(components[key])
}
}
}
加載組件
然後做一個組件來加載指定的組件
- template
<Teleport :to="'#' + item.id" :disabled="moveDisabled">
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>
{{item.title}}
</span>
</div>
</template>
<component
:is="$state.comp[item.key]"
v-bind="item.props"
>
</component>
</el-card>
</Teleport>
好吧,其實只需要使用 component 來加載,el-card 是為了外觀不是太難看,Teleport 是為了可以「穿越」的文檔的指定位置。
組件定位
如果組件只能在文檔末尾加載,那麼不是太好看,所以還需要一個「定位」功能,在文檔裏面指定加載位置。
我們可以直接在 md 格式的文檔裏面加一個div,設置屬性即可:
<div
id="test2"
data-key="testComponent"
data-props='{"msg":"div設置的屬性"}'
data-title="加載組件的測試"
>
加載中
</div>
- id:註冊組件時對應的key,指定要加載的組件。
- data-key: 組件的key,要加載哪個組件。
- data-props: 組件需要的props屬性,標準json格式。
- data-title: 組件上面顯示的標題。
- 為什麼用div?
因為還不會做 markdown-it 的插件。 - 為什麼用 data-*?
因為只有 id 和 data-* 被保留,其他屬性都被「吃掉」了。
這樣在查看文檔的時候,組件就會被加載到這個div裏面。
看看效果
在線編寫代碼、修改代碼、運行代碼
我知道有很多第三方網站提供了完整的在線寫代碼的功能,一些官方文檔也在用,但是總感覺有點「距離感」。因為需要點個連接打開新窗口,不知道大家有沒有體驗過。
對於一些簡單的演示代碼,還是覺得應該在一個頁面內實現,所以自己做了一個簡單的功能。
defineAsyncComponent
一開始用 script setup + defineAsyncComponent實現,在本地運行(開發模式)一切正常,但是發佈後(生成環境)就出問題了,模板部分死活加載不上來。
改為 setup方式,不行,嘗試其他方法也沒有搞定。但是又不想放棄這個功能,最後只好用 CDN的方式來實現。
iframe + CDN
搞不定問題怎麼辦?繞過去吧。於是開啟了古老的 iframe。
<iframe :src="src" style="width:100%;height:100%"></iframe>
import {
defineComponent,
watch,
ref
} from 'vue'
import config from '../config/index.js'
export default defineComponent({
name: 'el-doc-runcode',
inheritAttrs: false,
props: {
code: {
type: Object,
default: () => {
return {
id: 1,
js: '',
template: '',
style: ''
}
}
},
reload: Boolean
},
setup (props) {
const src = ref('')
// 用 Window 傳遞代碼
if (!window.__code) {
window.__code = {}
}
// 重新加載代碼
watch(() => props.reload, () => {
const id = props.code.id
window.__code[id] = props.code
src.value = `${config.baseUrl}runcode/index.html?id=${id}&rnd=${new Date().valueOf()}`
}, {immediate: true})
return {
src
}
}
})
運行代碼
首先用CDN加載vue.js等需要的文件,然後設置 template 和代碼即可。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/nfwt.ico" />
<link href="//unpkg.com/[email protected]/dist/index.css" rel="stylesheet"/>
<script src="//unpkg.com/[email protected]/dist/vue.global.js"></script>
<script src="//unpkg.com/[email protected]/dist/index.full.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>運行代碼</title>
</head>
<body>
<div id="app"></div>
<script >
// 使用 eval編譯js代碼的模板
const mysetup = `
(function setup (props, ctx) {
{{code}}
})
`
// 接收參數
const search = decodeURI(window.location.search)
const id = search.split('&')[0].replace('?id=','')
const code = top.window.__code[id]
const temp = code.template
const {
defineComponent,
defineAsyncComponent,
ref,
reactive,
// 其他需要演示的功能
nextTick
} = Vue
const App = {
template: temp, // 設置模板
setup (_props, _ctx) {
const tmpJs = code.js // 獲取js代碼
let fun = null // 轉換後的函數
try {
if (tmpJs)
fun = eval(mysetup.replace('{{code}}', tmpJs)) // 用 eval 把 字符串 變成js代碼
} catch (error) {
console.error('轉換出現異常:', error)
}
const re = typeof fun === 'function' ? fun : () => {}
return {
...re(_props, _ctx) // 運行函數,解構返回對象
}
}
}
const app = Vue.createApp(App)
// 掛載需要的第三方插件。
app.use(ElementPlus).mount("#app")
</script>
</body>
</html>
這樣我們就可以愉快的在線寫代碼了。
查看效果
//nfpress.gitee.io/nf-press-edit/1010/18_runcode
設置代碼的方式
可以點右上角,切換為編輯模式,體驗一下在線編寫文檔。好吧,有點簡陋。