Skip to content

Commit f385e21

Browse files
committed
Fix Vue compatibility (fix #790)
- Fix inability to instantiate reactive Vue components by 1) handling each child of #main instead of #main itself and 2) skipping elements that are already Vue instances - Retain previous behavior of processing basic Vue rendering without the need for a markdown <script> tag. - Update documentation and add live Vue examples - Update `index.html` files to include Vue.js and Vuep (CSS+JS)
1 parent c78cb11 commit f385e21

File tree

4 files changed

+126
-63
lines changed

4 files changed

+126
-63
lines changed

docs/index.html

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/dark.css" title="dark" disabled>
1515
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/buble.css" title="buble" disabled>
1616
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/pure.css" title="pure" disabled>
17+
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/vuep/dist/vuep.css">
1718

1819
<style>
1920
nav.app-nav li ul {
@@ -95,6 +96,8 @@
9596
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-bash.min.js"></script>
9697
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-markdown.min.js"></script>
9798
<script src="//cdn.jsdelivr.net/npm/prismjs/components/prism-nginx.min.js"></script>
99+
<script src="//cdn.jsdelivr.net/npm/vue@2/dist/vue.min.js"></script>
100+
<script src="//cdn.jsdelivr.net/npm/vuep/dist/vuep.min.js"></script>
98101
<script>
99102
((window.gitter = {}).chat = {}).options = {
100103
room: 'docsifyjs/Lobby'

docs/vue.md

+93-47
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,145 @@
1-
# Compatible with Vue
1+
# Vue compatibility
22

3-
You can write Vue components directly in the Markdown file, and it will be parsed. You can use this feature to write vue demo and documentation together.
3+
Docsify allows [Vue.js](https://vuejs.org) components to be added directly to you Markdown files. These components can greatly simplify working with data and adding reactivity to your content.
44

5-
## Basic usage
6-
7-
Load the Vue in `./index.html`.
5+
To get started, load either the production (minified) or development (unminified) version of Vue in your `index.html`:
86

97
```html
10-
<script src="//cdn.jsdelivr.net/npm/vue"></script>
11-
<script src="//cdn.jsdelivr.net/npm/docsify"></script>
8+
<!-- Production (minified) -->
9+
<script src="//cdn.jsdelivr.net/npm/vue@2/dist/vue.min.js"></script>
1210

13-
<!-- Or use the compressed files -->
14-
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
15-
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
11+
<!-- Development (unminified, with debugging info via console) -->
12+
<script src="//cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
1613
```
1714

18-
Then you can immediately write Vue code at Markdown file. `new Vue({ el: '#main' })` script is executed by default to create instance.
19-
20-
*README.md*
15+
## Basic rendering
2116

22-
````markdown
23-
# Vue guide
17+
Docsify will automatically render basic Vue content that does not require `data`, `methods`, or other instance features.
2418

25-
`v-for` usage.
19+
```markdown
20+
<button v-on:click.native="this.alert('Hello, World!')">Say Hello</button>
2621

27-
```html
2822
<ul>
29-
<li v-for="i in 10">{{ i }}</li>
23+
<li v-for="i in 3">{{ i }}</li>
3024
</ul>
3125
```
3226

27+
The HTML above will render the following:
28+
29+
<button v-on:click="this.alert('Hello, World!')">Say Hello</button>
30+
3331
<ul>
34-
<li v-for="i in 10">{{ i }}</li>
32+
<li v-for="i in 3">{{ i }}</li>
3533
</ul>
36-
````
3734

38-
You can manually initialize a Vue instance.
35+
## Advanced usage
3936

40-
*README.md*
37+
Vue components and templates that require `data`, `methods`, computed properties, lifecycle hooks, etc. require manually creating a new `Vue()` instance within a `<script>` tag in your markdown.
4138

4239
```markdown
43-
# Vue demo
40+
<div id="example-1">
41+
<p>{{ message }}</p>
42+
43+
<button v-on:click="hello">Say Hello</button>
4444

45-
<div id="main">hello {{ msg }}</div>
45+
<button v-on:click="counter -= 1">-</button>
46+
{{ counter }}
47+
<button v-on:click="counter += 1">+</button>
48+
</div>
49+
```
4650

51+
```markdown
4752
<script>
4853
new Vue({
49-
el: '#main',
50-
data: { msg: 'Vue' }
51-
})
54+
el: "#example-1",
55+
data: function() {
56+
counter: 0,
57+
message: "Hello, World!"
58+
},
59+
methods: {
60+
hello: function() {
61+
alert(this.message);
62+
}
63+
}
64+
});
5265
</script>
5366
```
5467

55-
!> In a Markdown file, only the script within the first script tag is executed.
68+
The HTML & JavaScript above will render the following:
69+
70+
<div id="example-1">
71+
<p>{{ message }}</p>
72+
73+
<button v-on:click="hello">Say Hello</button>
74+
75+
<button v-on:click="counter -= 1">-</button>
76+
{{ counter }}
77+
<button v-on:click="counter += 1">+</button>
78+
</div>
5679

57-
## Combine Vuep to write playground
80+
!> Only the first `<script>` tag in a markdown file is executed. If you are working with multiple Vue components, all `Vue` instances must be created within this tag.
5881

59-
[Vuep](https://github.com/QingWei-Li/vuep) is a component for rendering Vue components with live editor and preview. Supports Vue component spec and JSX.
82+
## Vuep playgrounds
6083

61-
*index.html*
84+
[Vuep](https://github.com/QingWei-Li/vuep) is a Vue component that provides a live editor and preview for Vue content. See the [vuep documentation](https://qingwei-li.github.io/vuep/) for details.
85+
86+
Add Vuep CSS and JavaScript to your `index.html`:
6287

6388
```html
64-
<!-- Inject CSS file -->
89+
<!-- Vuep CSS -->
6590
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/vuep/dist/vuep.css">
6691

67-
<!-- Inject JavaScript file -->
68-
<script src="//cdn.jsdelivr.net/npm/vue"></script>
69-
<script src="//cdn.jsdelivr.net/npm/vuep"></script>
70-
<script src="//cdn.jsdelivr.net/npm/docsify"></script>
71-
72-
<!-- or use the compressed files -->
73-
<script src="//cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
92+
<!-- Vuep JavaScript -->
7493
<script src="//cdn.jsdelivr.net/npm/vuep/dist/vuep.min.js"></script>
75-
<script src="//cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
7694
```
7795

78-
*README.md*
79-
```markdown
80-
# Vuep
96+
Add vuep markup to a markdown file (e.g. `README.md`):
8197

82-
<vuep template="#example"></vuep>
98+
```markdown
99+
<vuep template="#example-2"></vuep>
83100

84-
<script v-pre type="text/x-template" id="example">
101+
<script v-pre type="text/x-template" id="example-2">
85102
<template>
86103
<div>Hello, {{ name }}!</div>
87104
</template>
88105

89106
<script>
90107
module.exports = {
91-
data: function () {
108+
data: function() {
92109
return { name: 'Vue' }
93110
}
94111
}
95112
</script>
96113
</script>
97114
```
98115

99-
?> Example Refer to the [Vuep documentation](https://qingwei-li.github.io/vuep/).
116+
<vuep template="#example-2"></vuep>
117+
118+
<script v-pre type="text/x-template" id="example-2">
119+
<template>
120+
<div>Hello, {{ name }}!</div>
121+
</template>
122+
123+
<script>
124+
module.exports = {
125+
data: function() {
126+
return { name: 'World' }
127+
}
128+
}
129+
</script>
130+
</script>
131+
132+
<script>
133+
new Vue({
134+
el: "#example-1",
135+
data: {
136+
counter: 0,
137+
message: "Hello, World!"
138+
},
139+
methods: {
140+
hello: function() {
141+
alert(this.message);
142+
}
143+
}
144+
});
145+
</script>

index.html

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<link rel="stylesheet" href="/themes/vue.css" title="vue">
1010
<link rel="stylesheet" href="/themes/dark.css" title="dark" disabled>
1111
<link rel="stylesheet" href="/themes/buble.css" title="buble" disabled>
12+
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/vuep/dist/vuep.css">
1213
<style>
1314
nav.app-nav li ul {
1415
min-width: 100px;
@@ -85,6 +86,8 @@
8586
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
8687
<script src="//unpkg.com/prismjs/components/prism-markdown.min.js"></script>
8788
<script src="//unpkg.com/prismjs/components/prism-nginx.min.js"></script>
89+
<script src="//unpkg.com/vue/dist/vue.js"></script>
90+
<script src="//unpkg.com/vuep/dist/vuep.min.js"></script>
8891
</body>
8992

9093
</html>

src/core/render/index.js

+27-16
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ function executeScript() {
2626
return false;
2727
}
2828

29-
setTimeout(_ => {
30-
window.__EXECUTE_RESULT__ = new Function(code)();
31-
}, 0);
29+
new Function(code)();
3230
}
3331

3432
function formatUpdated(html, updated, fn) {
@@ -48,22 +46,35 @@ function renderMain(html) {
4846
}
4947

5048
this._renderTo('.markdown-section', html);
49+
5150
// Render sidebar with the TOC
5251
!this.config.loadSidebar && this._renderSidebar();
5352

54-
// Execute script
55-
if (
56-
this.config.executeScript !== false &&
57-
typeof window.Vue !== 'undefined' &&
58-
!executeScript()
59-
) {
60-
setTimeout(_ => {
61-
const vueVM = window.__EXECUTE_RESULT__;
62-
vueVM && vueVM.$destroy && vueVM.$destroy();
63-
window.__EXECUTE_RESULT__ = new window.Vue().$mount('#main');
64-
}, 0);
65-
} else {
66-
this.config.executeScript && executeScript();
53+
// Execute markdown <script>
54+
if (this.config.executeScript || 'Vue' in window) {
55+
executeScript();
56+
}
57+
58+
// Handle Vue content not handled by markdown <script>
59+
if ('Vue' in window) {
60+
const mainElm = document.querySelector('#main') || {};
61+
const childElms = mainElm.children || [];
62+
63+
for (let i = 0, len = childElms.length; i < len; i++) {
64+
const elm = childElms[i];
65+
const isValid = ['SCRIPT'].indexOf(elm.tagName) === -1;
66+
const isVue = Boolean(elm.__vue__ && elm.__vue__._isVue);
67+
68+
if (isValid && !isVue) {
69+
new window.Vue({
70+
mounted: function() {
71+
if (this.$children.length === 0) {
72+
this.$destroy;
73+
}
74+
},
75+
}).$mount(elm);
76+
}
77+
}
6778
}
6879
}
6980

0 commit comments

Comments
 (0)