Vue在线编译器

戳蓝字"

前端优选

"

关注我们哦

来源:CSDN 本文链接:https://blog.csdn.net/WangYangsea/article/details/95237722

现在网络上,有非常多的JS在线编译器,非常好用,特备是在调试某些片段代码的时候,比在本地重新新建文件来的方便快捷~ 非常流行的比如  JS.do、  jsfiddle、JSRUN 等等。

而对于Vue来说,在线编译器有时候会显得更加必要,因为初始化一个Vue项目还是需要花一点时间的~并且需要安卓很多的依赖,费时费力。现在也有很多JS在线编译器已经支持Vue代码了,另外流行的Vue框架)IView也有一个专门的在线编译器 IView Run,不止支持Vue,还支持IView 相关组件~。

接下来,我们两写一个功能相似的乞丐版Vue在线编译器 vue-running。

首先我们来看一下demo效果:

 vue在线编译效果

extend 和 $mount

在开始之前,我们先来了解一下Vue的两个不是很常用的API extend 和 $mount。

我们在使用 vue-cli + webpack构建一个新的工程的时候, 入口JS文件main.js中最后 总会看到这么一段:

new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

在创建一个Vue实例的时候,我们都有一个el属性,决定这个实例需要挂载在那个节点上(根节点),如果没有el属性,那么该实例处于未挂载状态。

  • Vue.extend()就是利用Vue的构造器功能,创建一个子类,但是属于未挂载状态;

  • $mount 就是一个手动去挂载Vue实例的方法。

我们可以看官方文档给的实例:

<div id="mount-point"></div>
// 创建构造器
var Profile = Vue.extend({
  template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
  data: function () {
    return {
      firstName: 'Walter',
      lastName: 'White',
      alias: 'Heisenberg'
    }
  }
})
// 创建 Profile 实例,并挂载到一个元素上。
new Profile().$mount('#mount-point')

结果如下:

<div id="mount-point">
 <p>Walter White aka Heisenberg</p>
</div>

vm.$mount()相关说明

「今天所说的 vue-running小demo,就是基于这两个属性做的」

分析

通常,我们Vue项目中的.vue文件构成如下:

<template>
  ......
</template>
<script>
export default {
  ......
</script>
<style scoped>
......
</style>
  • template 为HTML模板

  • script 为组件的数据、方法等

  • style css样式相关

我们回看上面extend方法,其实.vue文件中的 就代表 extend中 template,script中代表extend中的其他选项。style我们稍后再处理。

通过上面分析,首先我们得将.vue文件中的内容进行匹配分割,然后用Vue.extend()创建子类,最后挂载~。

首先我们在components文件夹下面新建:

  1. index.vue vue-running的显示页面

  2. edit.vue 编辑Vue代码的组件

  3. running.vue 最终编辑完的实例挂载之后显示的内容

首先我们看edit.vue:

<template>
  <div class="edit-box">
    <div class="btn-box">
      <button @click="handleClick">运行代码</button>
      <button class="edit" @click="edit">重新编辑</button>
    </div>
    <div class="style-box">
      <textarea :disabled="disabled" name="code" placeholder="请在此编写.vue文件" @input="handleChange"></textarea>
    </div>
  </div>
</template>
<script>
export default {
  name: 'edit',
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      currentValue: this.value,
      disabled: false
    }
  },
  methods: {
    handleChange (e) {
      const val = e.target.value
      this.$emit('input', val)
    },
    handleClick () {
      this.$emit('running')
      if (this.currentValue) {
        this.disabled = true
      }
    },
    edit () {
      this.disabled = false
    }
  }
}
</script>

其实功能比较简单,就是一个双向数据绑定的textarea输入框。外加 运行 和重新编辑 两个按钮,并将事件向外”广播“。

接下来我们看running.vue:

<template>
  <div class="hello">
    <h3 class="title">运行结果</h3>
    <div class="code-box" id="display"></div>
  </div>
</template>

<script>
import Vue from 'vue'
export default {
  name: 'running',
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      code: this.value,
      html: '',
      js: '',
      css: '',
      program: null
    }
  },
  watch: {
    value (val) {
      this.code = val
    }
  },
  methods: {
    getSource (source, type) {
      const regex = new RegExp(`<${type}[^>]*>`)
      let openingTag = source.match(regex)
      if (!openingTag) return ''
      else openingTag = openingTag[0]

      return source.slice(
        source.indexOf(openingTag) + openingTag.length,
        source.lastIndexOf(`</${type}>`)
      )
    },
    splitCode () {
      const script = this.getSource(this.code, 'script').replace(
        /export default/,
        'return '
      )
      const style = this.getSource(this.code, 'style')
      const template =
        '<div id="code-running">' +
        this.getSource(this.code, 'template') +
        '</div>'
      this.js = script
      this.css = style
      this.html = template
    },
    buildDom () {
      this.splitCode()
      if (this.html === '' || this.js === '') {
        this.$toast({
          msg: `请输入有效的Vue代码${Math.floor(Math.random() * 1000)}`
        })
        // eslint-disable-next-line semi
        return;
      }
      // eslint-disable-next-line no-new-func
      const common = new Function(this.js)()
      common.template = this.html
      const Template = Vue.extend(common)
      this.program = new Template()
      document.querySelector('#display').appendChild(this.program.$mount().$el)
      if (this.css !== '') {
        const styles = document.createElement('style')
        styles.type = 'text/css'
        styles.innerHTML = this.css
        document.getElementsByTagName('head')[0].appendChild(styles)
      }
    },
    reset () {
      document.getElementById('display').innerHTML = ''
      if (this.program) {
        this.program.$destroy()
      }
      this.program = null
    }
  }
}
</script>

稍作分析:

  • 该组件props接受一个value,string类型的,就是我们在线编辑的.vue文件代码;

  • data里面定义了 code: this.value ,另外定义了被分割好之后的代码片段js html css;

  • methods里面定义的方法 getSource() 通过正则匹配分割代码并去除最外层的

点个在看,大家都看 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值