基于vue的页面配置化的实现(下)——编辑器及生产

数字拓荒客
• 阅读 2829

在上一篇基于vue的页面配置化的实现(上)——模板开发中,我们完成了模板开发。

本篇主要分两个部分:

  1. 如何实现让运营在编辑器里配置这些参数,以及在编辑器里实时预览模板的效果呢
  2. 根据模板js和配置参数在服务端生成页面

编辑器

基于vue的页面配置化的实现(下)——编辑器及生产

先看下效果,最左侧是页面信息,如果有多个页面,则显示多栏。中间是实时预览效果,右侧则是配置datasource的地方。考虑到页面可能根据链接参数有不同表现,所以正上方是支持自定义链接参数以便于实时预览。右上角则是进行保存发布操作。

设计

在本地模板开发阶段,我们最后拿到了以下几个打包后的文件:

基于vue的页面配置化的实现(下)——编辑器及生产

接下来就是怎么使用这些js和json

基于vue的页面配置化的实现(下)——编辑器及生产

实现

首先我们远程拉取模板信息,实现过程不赘述,假设我们已经拿到了下面几个关键信息

  • home.js:模板的页面组件
  • settings.js:配置面板组件
  • datasource.json:模板配置字段
  • config.json:模板基础信息

左侧页面列表

根据模板 config.json 我们可以遍历出页面的路由信息

右侧配置面板

远程加载配置面板组件

这里的目的最终是要实现配置面板settings跟页面的datasource绑定在一起,实现通过配置面板来修改datasource。

  1. 封装一个远程tLoader的方法,拉取远程组件

    function loadJS(url = '') {
      if (!url) return
      if (!loadJS.cache) loadJS.cache = {}
      if (loadJS.cache[url]) return Promise.resolve()
      return new Promise((resolve, reject) => {
     _loadjs(
       url,
       () => {
         loadJS.cache[url] = 'cached'
         resolve()
       },
       () => {
         console.error(`${url}加载失败`)
         reject(new Error(`${url}加载失败`))
       }
     )
      })
    
      function _loadjs(url, fn, fail) {
     var script = document.createElement('script')
     script.src = url
     script.async = true
     script.onload = fn
     script.onerror = fail
     ;(document.body || document.head).appendChild(script)
      }
    }
    
    export default {
      requestCache: {},
      componentCache: {},
      getComponent(name, cdn) {
     return this.componentCache[name]
      },
      async load(name, cdnPath) {
     let component = this.getComponent(name)
     if (component) return component
     let request = ''
     let url = ''
     if (!this.requestCache[name]) {
       url = cdnPath
       // url += '?t=' + new Date().getTime()
       this.requestCache[name] = request = loadJS(cdnPath)
     } else request = this.requestCache[name]
     return await request.then((res) => {
       component = window[name]
       this.componentCache[name] = component
       return component
     }).catch(err => {
       console.log('加载失败', url)
       console.error(err)
     })
      }
    }
    
  2. 定义组件

    const template = await tLoader.load(name, `${url}?t=${new Date().getTime()}`)
    Vue.component('settings', template)
  3. 使用

    <component is="settings"></component>
  4. 将项目的datasource定义为全局变量,合并模板的data和项目的data

    const templateData = await axios.get('datasource.json')
    const projectData = await axios.get('projectDatasource.json')
    window['datasource'] = Object.merge(templateData, projectData)

正中间预览面板

原理:使用 iframe 加载页面,然后通过Vue.observable()绑定top.datasource
父页面
  1. 新建iframe

    <iframe
      ref="page-iframe"
      :key="iframeKey"
      frameborder="0"
      :src="pageRoute"
      @load="iframeMounted"
    />
    <script>
    export default {
      methods: {
       // iframe加载完成后,通知子页面可以开始加载模板的路由组件了
       iframeMounted() {
          this.post({
           type: 'initPage',
           data: {
             js: `${js}.js`, // 加载模板路由js的url地址,让子页面能够加载并加载
           }
         })
       }
      }
    }
    </script>

    pageRoute 是用来加载iframe地址的,可以动态更新路由参数。

iframe 页面
  1. 监听父页面传递过来的消息,并加载并定义模板路由组件

    window.addEventListener('message', function(d) {
         const { type, data } = d.data
         switch (type) {
           case 'initPage':
             // !!!,绑定父窗口的 datasource
             window['datasource'] = Vue.observable(top.datasource)
             // 挂载 page 的component,原理跟父页面的settings的加载方式一致
             const template = await tLoader.load(data.name, `${data.js}?t=${new Date().getTime()}`)
             Vue.component(data.name, template)
             this.current.name = data.name // 当前页面
             break
           default: break
         }
       })
  2. 加载路由组件

    <!--current.name 用于切换模板的路由-->
    <component
         :is="current.name"
         v-if="mounted"
         class="page"
       />

至此,编辑器的部分就完成了

服务端实现

本节不讨论如何存储模板和项目配置信息,存储的方案可以放在cdn上,也可以存储在数据库中;也不会讨论部署,只会讨论如何生成一个页面。

如果仔细看下来,大概能知道服务端要如何实现生产页面。还记得在本地模板开发的时候,本地预览的实现吗?没错,原理都是一致的。

实现

  1. 用 ejs 作为模板语言, 新建 index.ejs,用于渲染出html

    <!DOCTYPE html>
    <html lang="zh-CN">
      <head>
     <meta charset="utf-8">
     <meta name="renderer" content="webkit"/>
     <meta name="force-rendering" content="webkit"/>
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
     <meta name="viewport" id="viewport" content="width=device-width,initial-scale=1.0">
     <title></title>
     <style>
       html{
         width: 100%;
         height: 100%;
       }
       <%= styles %>
     </style>
     <!-- import vue and ui js -->
     <% for(var j of js) { %>
       <script src="<%=j%>"></script>
     <% } %>
      </head>
      <body>
     <div id="app"></div>
     
     <!-- template router js -->
     <% for(var j in interactjs) { %>
       <script src="<%=interactjs[j]%>"></script>
     <% } %>
     <script>
       /* 路由 */
       var routes = [
         <% for (var n of routes) { %>
           {
             <% for (var i in n) { %>
               <% if (i === 'component') { %>
                 <%- i %>: <%- "window['" + n[i] + "']"  %>,
               <% } else { %>
                 <%- i %>: <%- JSON.stringify(n[i]) %>,
               <% } %>
             <% } %>
           },
         <% } %>
       ]
       var router = new VueRouter({
         mode: 'hash',
         routes: routes
       });
       var datasource = new Vue.observable(<%- JSON.stringify(project) %>)
       var instance = new Vue({
         router: router,
         render: function (h, context) {
           return h(
             'div',
             {},
             [
              h('router-view', {
                on: {
                }
              }, null),
             ]
           )
         },
       }).$mount('#app');
     </script>
      </body>
    </html>
    
  2. 渲染模板

    const fs = require('fs')
    const request = require('request')
    const prettier = require('prettier')
    
    // 下载模板的路由组件 js
    /* const dlJs = (url, stream) => new Promise(resolve => {
     request(url).pipe(stream).on('finish', () => {
       resolve()
     })
    }) */
    
    // 模板路由组件 js
    const interactjs = {
      'home': `./home.js?t=${Date.now()}`
    }
    // 从模板的 config.json 读取路由信息
    const routes = require('./config.json')
    
    // 获取datasource.json
    const project = require('./datasource.json')
    
    // 获取ejs
    const pageTemplate = fs.readFileSync(path.join(__dirname, 'template/index.ejs'), 'utf8')
    
    // render 渲染
    ret = ejs.render(pageTemplate, {
     styles: styles.join(''),
     js: [ './vue.runtime.min.js', './vue-router.js' ],
     interactjs,
     css,
     routes,
     project,
    })
    
    // 格式化文档
    const prettierHtml = prettier.format(ret, {
      parser: 'html',
      printWidth: 80,
      singleQuote: true,
    })
    
    // 生成文件
    fs.writeFileSync(path.join(projectPath, 'index.html'), prettierHtml)
    
    // TODO
    // 将 ./*.js 的文件拷贝或下载到与index.html 同级目录下

    最后生成的工程跟我们在模板开发的时候本地预览的dist几乎一致的,只是生产不再需要settings

优化的思路: window 直接注入可以换成 system.js 异步加载路由组件
点赞
收藏
评论区
推荐文章
基于Vue3+TypeScript+ Vue-Cli4.0构建手机端模板脚手架
vue3h5template基于Vue3TypeScriptVueCli4.0vantuisassrem适配方案axios封装jssdk配置vconsole移动端调试,构建手机端模板脚手架项目地址:建议手机端查看Node版本要求VueCLI需要Node.js8.9或更高版本
Easter79 Easter79
4年前
tp5 修改自带success或error跳转模板页面
tp5修改自带success或error跳转模板页面我们在使用tp5或者tp3.2的时候,用的成功或者失败跳转提示页面一般是用框架的。在后续开发过程中,根据实际项目需要,也是可以更改的,在此分享一个自用的模板。首先是看一下tp框架自带的跳转模板页面,以tp5为例在config.php中,我
Jacquelyn38 Jacquelyn38
4年前
一篇文章带你使用Typescript封装一个Vue组件
搭建项目以及初始化配置vue create tsvuebtn这里使用了vueCLI3自定义选择的服务,我选择了ts、stylus等工具。然后创建完项目之后,进入项目。使用快捷命令code.进入Vscode编辑器(如果没有code.,需要将编辑器的「bin文件目录地址」放到环境变量的path中)。然后,我进入编辑器之后,进入设置工作区,随便设置一个
Wesley13 Wesley13
4年前
java代码生成工具之autoCode部署
autoCode介绍autoCode是一个代码生成工具。基于velocity模板引擎,采用SpringMVCmybatisFDUImysql此工具只负责生成代码文件,不会生成完整功能的应用程序.其特点主要有用户登陆每个用户有他自己独立的数据库连接配置和模板配置;数据源配置
徐小夕 徐小夕
5年前
轻松教你搞定组件的拖拽, 缩放, 多控制点伸缩和拖拽数据上报
最近笔者专注于研究可视化搭建平台的解决方案,分析了很多拖拽组件和页面动态化技术,也在H5Dooring(https://github.com/MrXujiang/h5Dooring)项目中做了很多技术实现,包括:搭建平台的组件设计和分类模式拖拽生成页面方案动态表单编辑器设计页面实时预览编译技术自定义组件和自定
LinMeng LinMeng
5年前
vue.config.js配置前端代理
//vue.config.js配置说明//官方vue.config.js参考文档https://cli.vuejs.org/zh/config/cssloaderoptions//这里只列一部分,具体配置参考文档module.exports{//部署生产环境和开发环境下的URL。//默认情况下,VueCLI
Stella981 Stella981
4年前
Elasticsearch Index Templates(索引模板)
索引模板,故名思议,就是创建索引的模板,模板中包含公共的配置(settings)和映射(Mapping),并包含一个简单触发条件,及条件满足时使用该模板创建一个新的索引。注意:模板只在创建索引时应用。更改模板不会对现有索引产生影响。当使用createindexAPI时,作为createindex调用的一部分定义的设置/映射将优先于模板中定义的任
Stella981 Stella981
4年前
Play之Scala
现在几乎每个web语言都会有这样那样的模板供你选择,如果你曾经使用过任何一种模板,我想模板这个概念你能很清晰的阐明,我借用类与对象的关系进行阐述:模板的功能就是将(含有模板元素的)页面实例化输出。每个人对模板的概念都不一而同,但模板干的事情几乎都是一致的渲染页面!Play的模板在HTML基础上直接基于Scala语言,模板文件通常存放在/app
Stella981 Stella981
4年前
Django框架详解之template
模板简介  将页面的设计和python的代码分离开会更干净简洁更容易维护。我们可以使用Django的模板系统来实现这种模式  python的模板:HTML代码模板语法  模板包括在使用时会被值替换掉的变量,和控制模板逻辑的标签变量  在Django模板中遍历复杂数据结构的关键是句点字符{语法}{{
铁扇公主 铁扇公主
2年前
JavaScript开发工具哪款好用?集成开发环境软件分享~
集成开发环境软件分享WebStorm中文版给大家,支持各种框架和技术,包括React、Angular、Vue.js、Node.js等,并提供了强大的代码编辑器、调试器、版本控制工具等,使得开发过程更加高效和流畅。框架和技术更新了项目模板我们重做了WebSt
飞码LowCode前端技术:如何便捷配置出页面 | 京东云技术团队
简介飞码是京东科技平台研发部研发的低代码产品,可使营销运营域下web页面快速搭建。本文将从三个方面来讲解如何便捷配置出页面,第一部分从数据、事件、业务支持三个方面进行分析,第二部分从模板与页面收藏与升级、页面UI结构、画布功能三个方面进行分析,第三部分从监
数字拓荒客
数字拓荒客
Lv1
愿你所在的城市,有暖阳,有清风,每天都过得很好。
文章
5
粉丝
0
获赞
0