运行 Vue.js 蠢萌的 Markdown 编辑器的时候遇到的坑

Author Avatar
patrickcty 5月 28, 2017

运行 Vue.js 蠢萌的 Markdown 编辑器的时候遇到的坑

在基本看了 Vue 的介绍之后我就准备运行 Vue.js 蠢萌的 Markdown 编辑器来看看效果,没想到遇到了不少坑…

Vue 的实例并没有初始化

浏览器里报错 _ is not defined

我 Google 了很久但是一直不得要点,最后放弃的时候 Google 了一下 _.debounce 这个函数。

_.debounce(func, [wait=0], [options])

创建一个防抖动函数。 该函数会在 wait 毫秒后调用 func 方法。 该函数提供一个 cancel 方法取消延迟的函数调用以及 flush 方法立即调用。 可以提供一个 options 对象决定如何调用 func 方法, options.leading 与|或 options.trailing 决定延迟前后如何触发。 func 会传入最后一次传入的参数给防抖动函数。 随后调用的防抖动函数返回是最后一次 func 调用的结果。

原来 _ 并不是一个变量,这个函数是来自于 underscore.js 这个模块的,于是接下来就引入这个模块就好了。

mark 模块也要引入

这里之所以能用这么少的代码就完成 MarkDown 编辑器是因为用了解析 MarkDown 的库,而这个库是来自 marked.js ,也就是说这个模块也需要引入。

注意引入的顺序

这里一共用到了四个 js 文件,其中

  • vue.js 是最重要的 js,也是最先被渲染的,因此应该放在第一个引入
  • md.js 这里初始化了 Vue 的实例,但是因为它用到了 Underscore.js 因此必须在它之后渲染,于是把它放在最后
  • underscore.js 这里是 _.debounce 的来源,没有这个函数页面不能正常显示,因此它要在第二个引入
  • marked.js 这是解析 MarkDown 的模块,在 _.debounce 之后才会调用,放在第三个引入

    正常运行的代码片段

    <script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.6/marked.min.js"></script>
    <script src="https://cdn.bootcss.com/underscore.js/1.8.3/underscore-min.js"></script>
    <script src="md.js"></script>

完整代码及分析

md.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Vue Markdown Editor</title>
        <link rel="stylesheet" type="text/css" href="md.css">
    </head>
        
    <body>
        <div id="editor">
            <textarea :value="input" @input="update"></textarea>
            <div v-html="compiledMarkdown"></div>
        </div>     
    </body>

    <script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.6/marked.min.js"></script>
    <script src="https://cdn.bootcss.com/underscore.js/1.8.3/underscore-min.js"></script>
    <script src="md.js"></script>

</html>

其中第十一行 textarea 是 Vue 中的文本区域组件,构成了编辑器的左半部分,里面的内容是由 input 中的值来指定的。而 @input 则监视了 textarea 的内容,有变化则调用 update 的内容。

md.css

html, body, #editor {
  margin: 0;
  height: 100%;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  color: #333;
}

textarea, #editor div {
  display: inline-block;
  width: 49%;
  height: 100%;
  vertical-align: top;
  box-sizing: border-box;
  padding: 0 20px;
}

textarea {
  border: none;
  border-right: 1px solid #ccc;
  resize: none;
  outline: none;
  background-color: #f6f6f6;
  font-size: 14px;
  font-family: 'Monaco', courier, monospace;
  padding: 20px;
}

code {
  color: #f66;
}

这个没什么好说的。

md.js

var app = new Vue({
  el: '#editor',
  data: {
    input: '# hello'
  },
  computed: {
    compiledMarkdown: function () {
      return marked(this.input, { sanitize: true })
    }
  },
  methods: {
    update: _.debounce(function (e) {
      this.input = e.target.value
    }, 300)
  }
})

这里是初始化了一个 Vue 的实例,其中 input 存放 md 源文件的内容。

computed 是计算属性,它使得 input 一发生改变计算属性就重新求值。详情可以看官方文档

而 methods 里面的 update 就是当检测到 DOM 的变化之后得到事件对象被 e 接收,然后再把新的内容 e.target.value 赋值给 input。而为了防止抖动,使用了 _.debounce。

关于事件对象:

而事件对象也有很多属性和方法,其中target属性是获取触发事件对象的目标,也就是绑定事件的元素,e.target表示该DOM元素,然后在获取其相应的属性值。
来源:http://www.imooc.com/qadetail/153498

在这里 _.debounce 接受了两个参数,第一个是要防抖的函数,第二个是需要延迟的毫秒数,也就是说刷新得不会太快。详情见具体文档

因此综上,当输入了新的内容会触发 update 对 input 进行更新,然后根据 computed 的性质使得 v-html 也就是页面进行了更新,于是一个简单高效的编辑器就这样完成了。

最后

这一切都归根结底与 js 没有学好…其实也没怎么系统地学习 js,只学过一些皮毛的内容…回头继续看 Vue 的语法…