需求背景
小程序上线需要提供用户服务协议和隐私政策条款的静态网页。需求包括:
- 将 Markdown 格式的协议文件转换为可访问的 HTML 页面
- 支持通过下拉框切换不同版本的协议
- 打包后部署到 uniCloud 前端网页托管
虽然可以直接用 Typora 导出 HTML,但这种方式缺乏交互能力(如版本切换)。使用 Vite + Vue3 构建一个轻量级项目,配合 Markdown 插件实现动态页面是更灵活的方案。
项目初始化
使用 Vite 的 Vue + TypeScript 模板创建项目:
pnpm create vite vue3-md --template vue-ts
cd vue3-md
pnpm install
bash
安装核心插件
unplugin-vue-markdown
将 Markdown 文件转换为 Vue 组件,支持在 Markdown 中使用 Vue 组件:
pnpm add -D unplugin-vue-markdown
bash
vite-plugin-pages
基于文件系统的自动路由,Markdown 文件自动生成对应路由:
pnpm add -D vite-plugin-pages
bash
markdown-it-anchor
为 Markdown 标题添加锚点,支持页面内跳转:
pnpm add -D markdown-it-anchor
bash
sass
样式预处理(可选,用于自定义页面样式):
pnpm add -D sass
bash
配置 Vite
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Markdown from 'unplugin-vue-markdown/vite'
import Pages from 'vite-plugin-pages'
import anchor from 'markdown-it-anchor'
export default defineConfig({
plugins: [
vue({
include: [/\.vue$/, /\.md$/]
}),
Markdown({
markdownItOptions: {
html: true, // 允许在 Markdown 中写 HTML 标签
linkify: true, // 自动将 URL 转换为可点击链接
typographer: true // 智能引号转换
},
markdownItSetup(md) {
md.use(anchor, {
permalink: anchor.permalink.headerInline()
})
}
}),
Pages({
extensions: ['vue', 'md']
})
]
})
typescript
html: true 是关键配置——它允许在 Markdown 文件中直接使用 HTML 标签和自定义样式。
配置路由
创建 src/router.ts:
import { createRouter, createWebHashHistory } from 'vue-router'
import routes from '~pages'
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
typescript
在 src/main.ts 中注册路由:
import { createApp } from 'vue'
import router from './router'
import App from './App.vue'
const app = createApp(App)
app.use(router)
app.mount('#app')
typescript
简化 App.vue 为仅包含路由出口:
<template>
<router-view />
</template>
vue
添加 Markdown 文件
将协议文件放入 src/pages/ 目录:
src/pages/
├── user-agreement.md # 用户服务协议
└── privacy.md # 隐私政策条款
text
配置默认路由,使访问根路径时自动跳转到用户协议页面:
// router.ts 中添加
routes.unshift({
path: '/',
redirect: '/user-agreement'
})
typescript
实现版本切换
创建一个包含下拉选择框的页面组件:
<!-- src/pages/layout.vue 或在具体页面中 -->
<template>
<div class="wrapper">
<header>
<select @change="handleChange">
<option value="1">V1 - 用户服务协议</option>
<option value="2">V2 - 用户服务协议</option>
<option value="3">V3 - 用户隐私协议</option>
</select>
</header>
<main>
<router-view />
</main>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const handleChange = (event) => {
const value = event.target.value
if (value === '2') {
router.push('/privacy')
} else {
router.push('/user-agreement')
}
}
</script>
<style lang="scss" scoped>
.wrapper {
padding: 20px 40px;
}
</style>
vue
构建与部署
构建静态文件
pnpm build
bash
构建产物在 dist/ 目录中,包含完整的 HTML、CSS、JS 文件。
上传到网页托管
方式一:手动上传
在 uniCloud 前端网页托管控制台中,上传 dist/ 目录的所有文件。
方式二:CLI 脚本上传(推荐)
编写部署脚本 scripts/publish.js:
const { execSync } = require('child_process')
const path = require('path')
const spaceName = 'your-space-name'
const provider = 'aliyun'
const distPath = path.resolve(__dirname, '../dist')
const prefix = '/'
const command = `uniCloud uploadFile --spaceName ${spaceName} --provider ${provider} --dir ${distPath} --prefix ${prefix}`
execSync(command, { stdio: 'inherit' })
javascript
执行部署:
node scripts/publish.js
bash
注意:CLI 部署前需要在 HBuilderX 中登录 DCloud 账号。
配置到小程序
将部署后的页面 URL 配置到 uni-starter 项目的 uni-id-pages/config.json 中:
{
"userAgreementUrl": "https://your-domain.com/user-agreement",
"privacyPolicyUrl": "https://your-domain.com/privacy"
}
json
配置完成后,小程序登录页面的"用户服务协议"和"隐私政策条款"链接即可正常跳转到对应的网页。
↑