diff --git a/docs/site/mobile.js b/docs/site/entry.js
similarity index 100%
rename from docs/site/mobile.js
rename to docs/site/entry.js
diff --git a/packages/vant-cli/README.md b/packages/vant-cli/README.md
index e78b541f5..207e7af4b 100644
--- a/packages/vant-cli/README.md
+++ b/packages/vant-cli/README.md
@@ -68,8 +68,5 @@ yarn add @vant/cli --dev
- [命令](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/commands.md)
- [配置指南](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/config.md)
- [目录结构](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/directory.md)
+- [桌面端组件](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/desktop.md)
- [更新日志](https://github.com/youzan/vant/tree/dev/packages/vant-cli/changelog.md)
-
-## 关于桌面端组件
-
-目前 Vant Cli 仅支持移动端组件的预览,桌面端组件暂不支持预览(欢迎 PR)。
diff --git a/packages/vant-cli/docs/config.md b/packages/vant-cli/docs/config.md
index ffca51a88..87fbea3ee 100644
--- a/packages/vant-cli/docs/config.md
+++ b/packages/vant-cli/docs/config.md
@@ -12,6 +12,7 @@
- [site.versions](#siteversions)
- [site.baiduAnalytics](#sitebaiduanalytics)
- [site.searchConfig](#sitesearchconfig)
+ - [site.hideSimulator](#sitehidesimulator)
- [Webpack](#webpack)
- [Babel](#babel)
- [默认配置](#-1)
@@ -165,6 +166,8 @@ module.exports = {
path: 'home',
// 导航项文案
title: '介绍',
+ // 是否隐藏当前页右侧的手机模拟器(默认不隐藏)
+ hideSimulator: true,
},
],
},
@@ -222,6 +225,13 @@ module.exports = {
配置内容参见 [docsearch](https://docsearch.algolia.com/docs/behavior)。
+### site.hideSimulator
+
+- Type: `boolean`
+- Default: `false`
+
+是否隐藏所有页面右侧的手机模拟器,默认不隐藏
+
### site.htmlPluginOptions
- Type: `object`
diff --git a/packages/vant-cli/docs/desktop.md b/packages/vant-cli/docs/desktop.md
new file mode 100644
index 000000000..af8b43b50
--- /dev/null
+++ b/packages/vant-cli/docs/desktop.md
@@ -0,0 +1,84 @@
+## 关于桌面端组件
+
+Vant Cli 也支持预览桌面端组件,你可以在组件的 `demo` 目录下新建一个 `.vue` 文件,并在组件的 `README` 中按如下格式声明要预览的组件:
+
+```html
+./demo/MyDemo.vue
+```
+
+`demo-code` 标签中间的文本为 `README` 到 `demo` 文件的相对路径。
+
+```
+button
+├─ demo # 组件示例
+│ └─ MyDemo.vue # 要预览的 demo 文件
+├─ index.js # 组件入口
+├─ index.less # 组件样式
+└─ README.md # 组件文档
+```
+
+
+
+`demo-code` 标签支持以下属性:
+
+| 名称 | 类型 | 描述 |
+| --------- | ------- | --------------------------------------- |
+| compact | boolean | 紧凑模式 |
+| transform | boolean | 防止预览区内 fixed 定位的元素飞出预览区 |
+| inline | boolean | 只显示组件本身,不显示预览区边框和代码 |
+
+### `compact`
+
+```html
+./demo/MyDemo.vue
+```
+
+
+
+### `transform`
+
+```html
+./demo/MyDemo.vue
+```
+
+
+
+### `inline`
+
+```html
+./demo/MyDemo.vue
+```
+
+
+
+### 去除手机模拟器
+
+对于 PC 端的组件,如果不需要右侧的手机模拟器,可以在 `vant.config.js` 文件中设置 `site.hideSimulator` 为 `true`,这样在所有页面都会隐藏手机模拟器,也可以只针对具体页面设置。
+
+```js
+module.exports = {
+ site: {
+ defaultLang: 'zh-CN',
+ hideSimulator: true, // 所有页面都不显示
+ locales: {
+ 'zh-CN': {
+ title: 'Vant',
+ description: '轻量、可靠的移动端 Vue 组件库',
+ hideSimulator: true, // 中文下所有页面都不显示
+ nav: [
+ {
+ title: '基础组件',
+ items: [
+ {
+ path: 'button',
+ title: 'Button 按钮',
+ hideSimulator: true, // 只针对某个页面不显示
+ },
+ ],
+ },
+ ],
+ },
+ },
+ },
+};
+```
diff --git a/packages/vant-cli/package.json b/packages/vant-cli/package.json
index a77cadfb6..75a7ae957 100644
--- a/packages/vant-cli/package.json
+++ b/packages/vant-cli/package.json
@@ -73,6 +73,7 @@
"commander": "^5.1.0",
"consola": "^2.12.2",
"conventional-changelog": "^3.1.21",
+ "copy-text-to-clipboard": "^3.0.1",
"cross-env": "^7.0.2",
"css-loader": "^3.5.3",
"eslint": "^6.8.0",
diff --git a/packages/vant-cli/site/desktop/App.vue b/packages/vant-cli/site/desktop/App.vue
index 5161bafbc..7375a108e 100644
--- a/packages/vant-cli/site/desktop/App.vue
+++ b/packages/vant-cli/site/desktop/App.vue
@@ -5,6 +5,7 @@
:config="config"
:versions="versions"
:simulator="simulator"
+ :has-simulator="hasSimulator"
:lang-configs="langConfigs"
>
@@ -28,6 +29,7 @@ export default {
return {
packageVersion,
simulator: `${path}mobile.html${location.hash}`,
+ hasSimulator: true,
};
},
@@ -67,16 +69,16 @@ export default {
watch: {
lang(val) {
setLang(val);
- this.setTitle();
+ this.setTitleAndToogleSimulator();
},
},
created() {
- this.setTitle();
+ this.setTitleAndToogleSimulator();
},
methods: {
- setTitle() {
+ setTitleAndToogleSimulator() {
let { title } = this.config;
if (this.config.description) {
@@ -84,6 +86,20 @@ export default {
}
document.title = title;
+
+ const navItems = this.config.nav.reduce(
+ (result, nav) => [...result, ...nav.items],
+ []
+ );
+ const current = navItems.find((item) => {
+ return item.path === this.$route.meta.name;
+ });
+
+ this.hasSimulator = !(
+ config.site.hideSimulator ||
+ this.config.hideSimulator ||
+ (current && current.hideSimulator)
+ );
},
},
};
diff --git a/packages/vant-cli/site/desktop/components/DemoPlayground.vue b/packages/vant-cli/site/desktop/components/DemoPlayground.vue
new file mode 100644
index 000000000..12f9d1587
--- /dev/null
+++ b/packages/vant-cli/site/desktop/components/DemoPlayground.vue
@@ -0,0 +1,188 @@
+
+
+
+
+
+
+
diff --git a/packages/vant-cli/site/desktop/components/index.vue b/packages/vant-cli/site/desktop/components/index.vue
index c087db09c..363c66559 100644
--- a/packages/vant-cli/site/desktop/components/index.vue
+++ b/packages/vant-cli/site/desktop/components/index.vue
@@ -8,12 +8,12 @@
@switch-version="$emit('switch-version', $event)"
/>
-
+
-
+
@@ -39,6 +39,7 @@ export default {
lang: String,
versions: Array,
simulator: String,
+ hasSimulator: Boolean,
langConfigs: Array,
config: {
type: Object,
diff --git a/packages/vant-cli/site/desktop/main.js b/packages/vant-cli/site/desktop/main.js
index 33c2a7708..c934ded76 100644
--- a/packages/vant-cli/site/desktop/main.js
+++ b/packages/vant-cli/site/desktop/main.js
@@ -2,18 +2,23 @@ import Vue from 'vue';
import App from './App';
import { router } from './router';
import { scrollToAnchor } from './utils';
+import DemoPlayground from './components/DemoPlayground';
if (process.env.NODE_ENV !== 'production') {
Vue.config.productionTip = false;
}
-new Vue({
- el: '#app',
- mounted() {
- if (this.$route.hash) {
- scrollToAnchor(this.$route.hash);
- }
- },
- render: h => h(App),
- router,
-});
+Vue.component(DemoPlayground.name, DemoPlayground);
+
+setTimeout(() => {
+ new Vue({
+ el: '#app',
+ mounted() {
+ if (this.$route.hash) {
+ scrollToAnchor(this.$route.hash);
+ }
+ },
+ render: (h) => h(App),
+ router,
+ });
+}, 0);
diff --git a/packages/vant-cli/src/compiler/gen-site-desktop-shared.ts b/packages/vant-cli/src/compiler/gen-site-desktop-shared.ts
index 0ce42825a..b52003d62 100644
--- a/packages/vant-cli/src/compiler/gen-site-desktop-shared.ts
+++ b/packages/vant-cli/src/compiler/gen-site-desktop-shared.ts
@@ -47,9 +47,9 @@ function resolveDocuments(components: string[]): DocumentItem[] {
if (locales) {
const langs = Object.keys(locales);
- langs.forEach(lang => {
+ langs.forEach((lang) => {
const fileName = lang === defaultLang ? 'README.md' : `README.${lang}.md`;
- components.forEach(component => {
+ components.forEach((component) => {
docs.push({
name: formatName(component, lang),
path: join(SRC_DIR, component, fileName),
@@ -57,7 +57,7 @@ function resolveDocuments(components: string[]): DocumentItem[] {
});
});
} else {
- components.forEach(component => {
+ components.forEach((component) => {
docs.push({
name: formatName(component),
path: join(SRC_DIR, component, 'README.md'),
@@ -65,26 +65,35 @@ function resolveDocuments(components: string[]): DocumentItem[] {
});
}
- const staticDocs = glob.sync(normalizePath(join(DOCS_DIR, '**/*.md'))).map(path => {
- const pairs = parse(path).name.split('.');
- return {
- name: formatName(pairs[0], pairs[1] || defaultLang),
- path,
- };
- });
+ const staticDocs = glob
+ .sync(normalizePath(join(DOCS_DIR, '**/*.md')))
+ .map((path) => {
+ const pairs = parse(path).name.split('.');
+ return {
+ name: formatName(pairs[0], pairs[1] || defaultLang),
+ path,
+ };
+ });
- return [...staticDocs, ...docs.filter(item => existsSync(item.path))];
+ return [...staticDocs, ...docs.filter((item) => existsSync(item.path))];
+}
+
+function genInstall() {
+ return `import Vue from 'vue';
+import PackageEntry from './package-entry';
+import './package-style';
+`;
}
function genImportDocuments(items: DocumentItem[]) {
return items
- .map(item => `import ${item.name} from '${normalizePath(item.path)}';`)
+ .map((item) => `import ${item.name} from '${normalizePath(item.path)}';`)
.join('\n');
}
function genExportDocuments(items: DocumentItem[]) {
return `export const documents = {
- ${items.map(item => item.name).join(',\n ')}
+ ${items.map((item) => item.name).join(',\n ')}
};`;
}
@@ -104,9 +113,12 @@ export function genSiteDesktopShared() {
const dirs = readdirSync(SRC_DIR);
const documents = resolveDocuments(dirs);
- const code = `${genImportConfig()}
+ const code = `${genInstall()}
+${genImportConfig()}
${genImportDocuments(documents)}
+Vue.use(PackageEntry);
+
${genExportConfig()}
${genExportDocuments(documents)}
${genExportVersion()}
diff --git a/packages/vant-cli/src/config/webpack.base.ts b/packages/vant-cli/src/config/webpack.base.ts
index 78e8382de..ebc1d1824 100644
--- a/packages/vant-cli/src/config/webpack.base.ts
+++ b/packages/vant-cli/src/config/webpack.base.ts
@@ -62,6 +62,15 @@ if (existsSync(tsconfigPath)) {
);
}
+const VUE_LOADER = {
+ loader: 'vue-loader',
+ options: {
+ compilerOptions: {
+ preserveWhitespace: false,
+ },
+ },
+};
+
export const baseConfig: WebpackConfig = {
mode: 'development',
resolve: {
@@ -71,17 +80,7 @@ export const baseConfig: WebpackConfig = {
rules: [
{
test: /\.vue$/,
- use: [
- CACHE_LOADER,
- {
- loader: 'vue-loader',
- options: {
- compilerOptions: {
- preserveWhitespace: false,
- },
- },
- },
- ],
+ use: [CACHE_LOADER, VUE_LOADER],
},
{
test: /\.(js|ts|jsx|tsx)$/,
@@ -113,7 +112,7 @@ export const baseConfig: WebpackConfig = {
},
{
test: /\.md$/,
- use: [CACHE_LOADER, 'vue-loader', '@vant/markdown-loader'],
+ use: [CACHE_LOADER, VUE_LOADER, '@vant/markdown-loader'],
},
],
},
diff --git a/packages/vant-cli/yarn.lock b/packages/vant-cli/yarn.lock
index 91e06334d..198230119 100644
--- a/packages/vant-cli/yarn.lock
+++ b/packages/vant-cli/yarn.lock
@@ -3945,6 +3945,11 @@ copy-descriptor@^0.1.0:
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
+copy-text-to-clipboard@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.npm.taobao.org/copy-text-to-clipboard/download/copy-text-to-clipboard-3.0.1.tgz?cache=0&sync_timestamp=1613626493019&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcopy-text-to-clipboard%2Fdownload%2Fcopy-text-to-clipboard-3.0.1.tgz#8cbf8f90e0a47f12e4a24743736265d157bce69c"
+ integrity sha1-jL+PkOCkfxLkokdDc2Jl0Ve85pw=
+
core-js-compat@^3.6.2:
version "3.6.4"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.4.tgz#938476569ebb6cda80d339bcf199fae4f16fff17"
diff --git a/packages/vant-markdown-loader/src/extract-demo.js b/packages/vant-markdown-loader/src/extract-demo.js
new file mode 100644
index 000000000..b142fce78
--- /dev/null
+++ b/packages/vant-markdown-loader/src/extract-demo.js
@@ -0,0 +1,35 @@
+const path = require('path');
+const fs = require('fs');
+const parser = require('./md-parser');
+
+function hyphenate(str) {
+ return str.replace(/\B([A-Z])/g, '-$1').toLowerCase();
+}
+
+module.exports = function extraDemo(content) {
+ const markdownDir = path.dirname(this.resourcePath);
+ const demoLinks = [];
+
+ content = content.replace(
+ /([\s\S]*?)<\/demo-code>/g,
+ function (_, attrs, link) {
+ link = link.trim(); // 去换行符
+ const tag = hyphenate(path.basename(link, '.vue'));
+ const fullLink = path.join(markdownDir, link);
+ demoLinks.indexOf(fullLink) === -1 && demoLinks.push(fullLink);
+ const demoContent = fs.readFileSync(fullLink, { encoding: 'utf8' });
+ const demoParseredContent = parser.render(
+ '```html\n' + demoContent + '\n```'
+ );
+ return `
+
+ <${tag} />
+
+ `;
+ }
+ );
+
+ return [content, demoLinks];
+};
diff --git a/packages/vant-markdown-loader/src/index.js b/packages/vant-markdown-loader/src/index.js
index d04430519..5db6452e7 100644
--- a/packages/vant-markdown-loader/src/index.js
+++ b/packages/vant-markdown-loader/src/index.js
@@ -1,59 +1,61 @@
+const path = require('path');
const loaderUtils = require('loader-utils');
-const MarkdownIt = require('markdown-it');
-const markdownItAnchor = require('markdown-it-anchor');
const frontMatter = require('front-matter');
-const highlight = require('./highlight');
+const parser = require('./md-parser');
const linkOpen = require('./link-open');
const cardWrapper = require('./card-wrapper');
-const { slugify } = require('transliteration');
+const extractDemo = require('./extract-demo');
+const sideEffectTags = require('./side-effect-tags');
+
+function camelize(str) {
+ return str.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : ''));
+}
function wrapper(content) {
+ let demoLinks;
+ let styles;
+ [content, demoLinks] = extractDemo.call(this, content);
+ [content, styles] = sideEffectTags(content);
content = cardWrapper(content);
- content = escape(content);
-
return `
-
+
-
+${styles.join('\n')}
`;
}
-const parser = new MarkdownIt({
- html: true,
- highlight,
-}).use(markdownItAnchor, {
- level: 2,
- slugify,
-});
-
-module.exports = function(source) {
+module.exports = function (source) {
let options = loaderUtils.getOptions(this) || {};
this.cacheable && this.cacheable();
@@ -74,5 +76,5 @@ module.exports = function(source) {
linkOpen(parser);
}
- return options.wrapper(parser.render(source), fm);
+ return options.wrapper.call(this, parser.render(source), fm);
};
diff --git a/packages/vant-markdown-loader/src/md-parser.js b/packages/vant-markdown-loader/src/md-parser.js
new file mode 100644
index 000000000..3940d886f
--- /dev/null
+++ b/packages/vant-markdown-loader/src/md-parser.js
@@ -0,0 +1,14 @@
+const MarkdownIt = require('markdown-it');
+const markdownItAnchor = require('markdown-it-anchor');
+const highlight = require('./highlight');
+const { slugify } = require('transliteration');
+
+const parser = new MarkdownIt({
+ html: true,
+ highlight,
+}).use(markdownItAnchor, {
+ level: 2,
+ slugify,
+});
+
+module.exports = parser;
diff --git a/packages/vant-markdown-loader/src/side-effect-tags.js b/packages/vant-markdown-loader/src/side-effect-tags.js
new file mode 100644
index 000000000..a7f99fd5b
--- /dev/null
+++ b/packages/vant-markdown-loader/src/side-effect-tags.js
@@ -0,0 +1,14 @@
+module.exports = function sideEffectTags(content) {
+ const styles = [];
+
+ // 从模版中移除 script 标签
+ content = content.replace(/