nf-Press —— 在线文档也可以加载组件和编写代码

简介: 上一篇 juejin.cn/post/707482… 介绍了一下基本功能,这里介绍一下关于代码方面的功能

image.png


如果帮助文档可以加载组件,那么在介绍的同时就可以运行演示demo,是不是很酷?

如果可以在线修改运行代码,那么是不是更容易理解?


上一篇 juejin.cn/post/707482… 介绍了一下基本功能,这里介绍一下关于代码方面的功能


源码和演示



gitee.com/nfpress/nf-…


nfpress.gitee.io/nf-press-ed… ]


加载组件、运行组件



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}} &nbsp; &nbsp; 
            </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里面。


看看效果


image.png


在线编写代码、修改代码、运行代码



我知道有很多第三方网站提供了完整的在线写代码的功能,一些官方文档也在用,但是总感觉有点“距离感”。因为需要点个连接打开新窗口,不知道大家有没有体验过。


对于一些简单的演示代码,还是觉得应该在一个页面内实现,所以自己做了一个简单的功能。


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="https://unpkg.com/element-plus@1.2.0-beta.3/dist/index.css" rel="stylesheet"/>
    <script src="https://unpkg.com/vue@3.2.31/dist/vue.global.js"></script>
    <script src="https://unpkg.com/element-plus@2.1.4/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-ed…




设置代码的方式



可以点右上角,切换为编辑模式,体验一下在线编写文档。好吧,有点简陋。



相关文章
|
JavaScript
如何在fastadmin中不依赖于tab写一个选项卡.
如何在fastadmin中不依赖于tab写一个选项卡.
224 0
|
9月前
|
Python
【python自动化】Playwright基础教程(五)事件操作②悬停&输入&清除精讲
【python自动化】Playwright基础教程(五)事件操作②悬停&输入&清除精讲
208 0
|
前端开发 JavaScript 定位技术
iOS 逆向编程(十六)DZMCycript 脚本使用(封装了常用的快捷函数,后续会继续添加)
iOS 逆向编程(十六)DZMCycript 脚本使用(封装了常用的快捷函数,后续会继续添加)
147 0
|
前端开发
前端hook项目pc总结笔记-postgrest方法拼接扩展
前端hook项目pc总结笔记-postgrest方法拼接扩展
113 0
前端hook项目pc总结笔记-postgrest方法拼接扩展
|
Python
Python 自动化-pywinauto遍历展示程序的所有菜单项,菜单栏menu_select()操作方法的使用
Python 自动化-pywinauto遍历展示程序的所有菜单项,菜单栏menu_select()操作方法的使用
720 0
Python 自动化-pywinauto遍历展示程序的所有菜单项,菜单栏menu_select()操作方法的使用
|
小程序
小程序封装tab组件
小程序封装tab组件
|
测试技术
一起谈.NET技术,VS2010 测试功能之旅:编码的UI测试(4)-通过编写测试代码的方式建立UI测试(上)
  回顾   在之前的入门篇系列中,分别介绍了一个简单的示例, 操作动作的录制原理,通过修改UIMap.UItest文件控制操作动作代码的生成,对象的识别原理。接下来正式进入我们UI测试的进阶篇,在这一章,将讲述如何初步通过自己编写代码的方式来建立UI测试。
884 0
|
测试技术 数据库
一起谈.NET技术,VS2010 测试功能之旅:编码的UI测试(4)-通过编写测试代码的方式建立UI测试(下)
  回顾   最近比较忙,距离上次更新的时间较久,见谅。   在本章上部分,介绍了“添加用户”窗口的测试代码编写。想必大家也看到了,在UIMap.cs文件中实现自定义编码是一件很轻松的事情,接下来将介绍下个部分,查询用户窗体的测试代码的编写,以及他们测试的关联。
794 0
|
XML 测试技术 数据安全/隐私保护
一起谈.NET技术,VS2010测试功能之旅:编码的UI测试(2)-操作动作的录制原理(上)
  回顾    在之前我们介绍了如何用VS2010的UI测试功能创建一个简单的示例,大致描述了如何使用编码的UI测试进行录制和回放,在这章会着重描述VS2010是如何录制操作,并且生成代码,以及初步介绍如何通过自己写代码的方式进行测试。
1157 0
|
测试技术 数据安全/隐私保护
一起谈.NET技术,VS2010测试功能之旅:编码的UI测试(2)-操作动作的录制原理(下)
  回顾   在本章上部分介绍了操作动作的录制原理,描述了操作动作是如何录制,UIMap.uitest和UIMap.Designer.cs的代码如何生成,以及他们的结构。在这个部分,将着重说明如何通过修改UIMap1.uitest文件的操作动作部分的代码来控制UIMap1.Designer.cs操作动作部分代码的生成,实现第一种方式的自定义编码。
1060 0