13 - Vue3 UI Framework - 完善官網


為了提升用戶體驗,今天我們來對 jeremy-ui 官網做一個優化 🚀

返回閱讀列表點擊 這里

Markdown 解析支持 🗒️

習慣用 markdown 語法編輯,所以我們增加項目源碼對 markdown 的支持,雖然即便這樣做依然無法和 JeremyPress 或者 VuePress 相比,但是至少不用糾結於原生 html 了,能夠在一定程度上解決排版問題。

我們需要增加一個 plugins 文件夾,並且在此文件夾下創建一個 md.ts 的文件,代碼如下:

import path from 'path'
import fs from 'fs'
import marked from 'marked'
const mdToJs = str => {
  const content = JSON.stringify(marked(str))
  return `export default ${content}`
}

export function md() {
  return {
    configureServer: [
      async ({ app }) => {
        app.use(async (ctx, next) => {
          if (ctx.path.endsWith('.md')) {
            ctx.type = 'js'
            const filePath = path.join(process.cwd(), ctx.path)
            ctx.body = mdToJs(fs.readFileSync(filePath).toString())
          } else {
            await next()
          }
        })
      },
    ],
    transforms: [{
      test: context => context.path.endsWith('.md'),
      transform: ({ code }) => mdToJs(code)
    }]
  }
}

應該看到,這里我們需要依賴 marked 這個 npm 庫,運行項目之前,需要先安裝一下:

npm install marked --save

另外,我們還需要在項目的根目錄下創建 vite.config.ts 文件,並對 markdown 插件做一下配置:

import { md } from "./plugins/md";

export default {
  plugins: [md()],
};

GitHub Markdown 樣式支持 ⛵

我們可以使用 github-markdown-css 這個庫來獲取樣式表

npm install github-markdown-css --save

安裝完成后,在 main.ts 中引入

import 'github-markdown-css'

最后,我們對 Guidance.vue 做下配置以便 markdown 文件以及 markdown 樣式能夠在項目中被正確的解析:

<template>
  <article class="markdown-body" v-html="md"></article>
</template>
<script>
import { ref } from "vue";
export default {
  props: {
    path: {
      type: String,
      required: true,
    },
  },
  setup(props) {
    const md = ref(null);
    import(`../markdown/${props.path}.md`).then(
      (res) => (md.value = res.default)
    );
    return { md };
  },
};
</script>

代碼展示 💻

參考 ElementUI 手冊,我們發現不僅展示了組件,還會給出例子所使用的代碼,我們也在官網中增加查看代碼的功能。

我們可以在 vite 初始化的時候配置,即在 vite.config.ts 文件中做配置:

// @ts-nocheck
import { md } from "./plugins/md";
import fs from 'fs'
import { baseParse } from '@vue/compiler-core'

export default {
  base: '/',//指定打包后文件的默認引用路徑
  assetsDir: 'assets',
  plugins: [md()],
  vueCustomBlockTransforms: {
    example: (options) => {
      const { code, path } = options
      const file = fs.readFileSync(path).toString()
      const parsed = baseParse(file).children.find(n => n.tag === 'example')
      const title = parsed.children[0].content
      const main = file.split(parsed.loc.source).join('').trim()
      return `export default function (Component) {
        Component.__sourceCode = ${JSON.stringify(main)
        }
        Component.__sourceCodeTitle = ${JSON.stringify(title)}
      }`.trim()
    }
  }
};

注意

這里我們通過 // @ts-nocheck 注釋,來忽略靜態報錯

代碼高亮顯示支持 🏳️‍🌈

我們可以用 prismjs 庫來獲得代碼高亮,先安裝

npm install prismjs --save

然后,再在需要使用的地方,分別引入 prismjsprismjs/themes/prism.css,即可開始使用

prismjs 的工作原理,是構造一個對象,並綁定到 window 上,所以在模板中使用的時候,需要先獲取 window.Prism,再在 setupreturn 出去。Prism 對象的常見用例如下:

Prism.highlight(
    [sourceCode],
    Prism.languages.html,
    'html'
)

該對象上提供一個名為 highlight 的方法,該方法要求傳入 3 個參數,按順序分別如下

  1. 源代碼
  2. 作為代碼進行解析
  3. 作為代碼進行顯示(渲染)

最后,我們再在 Content.vue 文件中配置 Prism 以便內容中涉及到代碼的部分都能被高亮的顯示:

<template>
  <h1>{{ title }}</h1>
  <br />
  <div
    class="container"
    v-for="({ ...component }, index) in components"
    :key="index"
  >
    <jeremy-card class="example">
      <h2>{{ component.__sourceCodeTitle }}</h2>
      <br />
      <component :is="component" />
      <br />
      <br />
      <code class="markdown-body">
        <pre
          v-if="visibility[index]"
          v-html="
            Prism.highlight(
              component.__sourceCode,
              Prism.languages.html,
              'html'
            )
          "
        ></pre>
      </code>

      <button class="toggle" @click="toggle(index)">
        <span class="close" v-if="visibility[index]">
          △
          <span class="desp">隱藏代碼</span>
        </span>
        <span class="open" v-else>
          ▽
          <span class="desp">顯示代碼</span>
        </span>
      </button>
    </jeremy-card>
    <br />
  </div>
  <jeremy-table bordered>
    <thead>
      <tr>
        <th v-for="(head, index) in heads" :key="index">{{ head.name }}</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(attribute, index) in attributes" :key="index">
        <td v-for="key in keys" :key="key" v-html="attribute[key]"></td>
      </tr>
    </tbody>
  </jeremy-table>
</template>

<script lang="ts">
import JeremyButtons from "../components/contents/Button";
import JeremyCards from "../components/contents/Card";
import JeremyDialogs from "../components/contents/Dialog";
import JeremyInputs from "../components/contents/Input";
import JeremySwitchs from "../components/contents/Switch";
import JeremyTables from "../components/contents/Table";
import JeremyTabss from "../components/contents/Tabs";

import { ref } from "vue";
import { JeremyCard, JeremyTable } from "jeremy-ui"
import "prismjs";

const Prism = (window as any).Prism;

const JeremyMap = {
  Button: JeremyButtons,
  Card: JeremyCards,
  Dialog: JeremyDialogs,
  Input: JeremyInputs,
  Switch: JeremySwitchs,
  Table: JeremyTables,
  Tabs: JeremyTabss,
};

export default {
  props: {
    name: {
      type: String,
      required: true,
    },
    title: {
      type: String,
      required: true,
    },
  },
  components: {
    JeremyCard,
    JeremyTable,
  },
  setup(props) {
    const { name, title } = props;
    const heads = [
      { name: "參數", identifier: "attr" },
      { name: "含義", identifier: "desp" },
      { name: "類型", identifier: "type" },
      { name: "可選值", identifier: "values" },
      { name: "默認值", identifier: "default" },
    ];
    const keys = heads.map((item: any) => item.identifier);

    const { components, attributes } = JeremyMap[name];
    const visibility = ref(components.map((item) => false));
    const toggle = (index) => {
      visibility.value[index] = !visibility.value[index];
    };
    return {
      title,
      Prism,
      heads,
      keys,
      components,
      attributes,
      visibility,
      toggle,
    };
  },
};
</script>

另外,我們還需要在 main.ts 中引入代碼樣式:

import "prismjs/themes/prism-solarizedlight.css"

注意

樣式可以根據自己的喜好進行選擇,我這里選的是 prism-solarizedlight

除此之外,查看 prism 主題包可以看到其他的樣式哦

image-20211223095336895

展開/關閉代碼 💡

通過一個開關事件去控制代碼的顯示和隱藏

需要在 Content.vue 文件中配置一下:

<button class="toggle" @click="toggle(index)">
   <span class="close" v-if="visibility[index]">        △
      <span class="desp">隱藏代碼</span>
   </span>
   <span class="open" v-else>
      ▽
      <span class="desp">顯示代碼</span>
   </span>
</button>

修改 UI 引用路徑 🔉

官網的 UI 框架引用改成來自 npm ,這樣能夠更好的提升用戶體驗。先安裝:

npm install jeremy-ui --save

再在 main.ts 中引用樣式表:

import 'jeremy-ui/lib/jeremy.css'

最后,修改每個例子中的引用即可。

效果展示 🎉

opt

項目地址 🎁

GitHub: https://github.com/JeremyWu917/jeremy-ui

官網地址 🌍

JeremyUI: https://ui.jeremywu.top

感謝閱讀 ☕


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM