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

运行 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 之后才会调用,放在第三个引入

    正常运行的代码片段

    1
    2
    3
    4
    <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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 的语法…